147 lines · c
1// SPDX-License-Identifier: GPL-2.0+2 3#include "fdma_api.h"4 5#include <linux/bits.h>6#include <linux/etherdevice.h>7#include <linux/types.h>8 9/* Add a DB to a DCB, providing a callback for getting the DB dataptr. */10static int __fdma_db_add(struct fdma *fdma, int dcb_idx, int db_idx, u64 status,11 int (*cb)(struct fdma *fdma, int dcb_idx,12 int db_idx, u64 *dataptr))13{14 struct fdma_db *db = fdma_db_get(fdma, dcb_idx, db_idx);15 16 db->status = status;17 18 return cb(fdma, dcb_idx, db_idx, &db->dataptr);19}20 21/* Add a DB to a DCB, using the callback set in the fdma_ops struct. */22int fdma_db_add(struct fdma *fdma, int dcb_idx, int db_idx, u64 status)23{24 return __fdma_db_add(fdma,25 dcb_idx,26 db_idx,27 status,28 fdma->ops.dataptr_cb);29}30 31/* Add a DCB with callbacks for getting the DB dataptr and the DCB nextptr. */32int __fdma_dcb_add(struct fdma *fdma, int dcb_idx, u64 info, u64 status,33 int (*dcb_cb)(struct fdma *fdma, int dcb_idx, u64 *nextptr),34 int (*db_cb)(struct fdma *fdma, int dcb_idx, int db_idx,35 u64 *dataptr))36{37 struct fdma_dcb *dcb = fdma_dcb_get(fdma, dcb_idx);38 int i, err;39 40 for (i = 0; i < fdma->n_dbs; i++) {41 err = __fdma_db_add(fdma, dcb_idx, i, status, db_cb);42 if (unlikely(err))43 return err;44 }45 46 err = dcb_cb(fdma, dcb_idx, &fdma->last_dcb->nextptr);47 if (unlikely(err))48 return err;49 50 fdma->last_dcb = dcb;51 52 dcb->nextptr = FDMA_DCB_INVALID_DATA;53 dcb->info = info;54 55 return 0;56}57EXPORT_SYMBOL_GPL(__fdma_dcb_add);58 59/* Add a DCB, using the preset callbacks in the fdma_ops struct. */60int fdma_dcb_add(struct fdma *fdma, int dcb_idx, u64 info, u64 status)61{62 return __fdma_dcb_add(fdma,63 dcb_idx,64 info, status,65 fdma->ops.nextptr_cb,66 fdma->ops.dataptr_cb);67}68EXPORT_SYMBOL_GPL(fdma_dcb_add);69 70/* Initialize the DCB's and DB's. */71int fdma_dcbs_init(struct fdma *fdma, u64 info, u64 status)72{73 int i, err;74 75 fdma->last_dcb = fdma->dcbs;76 fdma->db_index = 0;77 fdma->dcb_index = 0;78 79 for (i = 0; i < fdma->n_dcbs; i++) {80 err = fdma_dcb_add(fdma, i, info, status);81 if (err)82 return err;83 }84 85 return 0;86}87EXPORT_SYMBOL_GPL(fdma_dcbs_init);88 89/* Allocate coherent DMA memory for FDMA. */90int fdma_alloc_coherent(struct device *dev, struct fdma *fdma)91{92 fdma->dcbs = dma_alloc_coherent(dev,93 fdma->size,94 &fdma->dma,95 GFP_KERNEL);96 if (!fdma->dcbs)97 return -ENOMEM;98 99 return 0;100}101EXPORT_SYMBOL_GPL(fdma_alloc_coherent);102 103/* Allocate physical memory for FDMA. */104int fdma_alloc_phys(struct fdma *fdma)105{106 fdma->dcbs = kzalloc(fdma->size, GFP_KERNEL);107 if (!fdma->dcbs)108 return -ENOMEM;109 110 fdma->dma = virt_to_phys(fdma->dcbs);111 112 return 0;113}114EXPORT_SYMBOL_GPL(fdma_alloc_phys);115 116/* Free coherent DMA memory. */117void fdma_free_coherent(struct device *dev, struct fdma *fdma)118{119 dma_free_coherent(dev, fdma->size, fdma->dcbs, fdma->dma);120}121EXPORT_SYMBOL_GPL(fdma_free_coherent);122 123/* Free virtual memory. */124void fdma_free_phys(struct fdma *fdma)125{126 kfree(fdma->dcbs);127}128EXPORT_SYMBOL_GPL(fdma_free_phys);129 130/* Get the size of the FDMA memory */131u32 fdma_get_size(struct fdma *fdma)132{133 return ALIGN(sizeof(struct fdma_dcb) * fdma->n_dcbs, PAGE_SIZE);134}135EXPORT_SYMBOL_GPL(fdma_get_size);136 137/* Get the size of the FDMA memory. This function is only applicable if the138 * dataptr addresses and DCB's are in contiguous memory.139 */140u32 fdma_get_size_contiguous(struct fdma *fdma)141{142 return ALIGN(fdma->n_dcbs * sizeof(struct fdma_dcb) +143 fdma->n_dcbs * fdma->n_dbs * fdma->db_size,144 PAGE_SIZE);145}146EXPORT_SYMBOL_GPL(fdma_get_size_contiguous);147