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. */ 10 static 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. */ 22 int 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. */ 32 int __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 } 57 EXPORT_SYMBOL_GPL(__fdma_dcb_add); 58 59 /* Add a DCB, using the preset callbacks in the fdma_ops struct. */ 60 int 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 } 68 EXPORT_SYMBOL_GPL(fdma_dcb_add); 69 70 /* Initialize the DCB's and DB's. */ 71 int 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 } 87 EXPORT_SYMBOL_GPL(fdma_dcbs_init); 88 89 /* Allocate coherent DMA memory for FDMA. */ 90 int 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 } 101 EXPORT_SYMBOL_GPL(fdma_alloc_coherent); 102 103 /* Allocate physical memory for FDMA. */ 104 int 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 } 114 EXPORT_SYMBOL_GPL(fdma_alloc_phys); 115 116 /* Free coherent DMA memory. */ 117 void fdma_free_coherent(struct device *dev, struct fdma *fdma) 118 { 119 dma_free_coherent(dev, fdma->size, fdma->dcbs, fdma->dma); 120 } 121 EXPORT_SYMBOL_GPL(fdma_free_coherent); 122 123 /* Free virtual memory. */ 124 void fdma_free_phys(struct fdma *fdma) 125 { 126 kfree(fdma->dcbs); 127 } 128 EXPORT_SYMBOL_GPL(fdma_free_phys); 129 130 /* Get the size of the FDMA memory */ 131 u32 fdma_get_size(struct fdma *fdma) 132 { 133 return ALIGN(sizeof(struct fdma_dcb) * fdma->n_dcbs, PAGE_SIZE); 134 } 135 EXPORT_SYMBOL_GPL(fdma_get_size); 136 137 /* Get the size of the FDMA memory. This function is only applicable if the 138 * dataptr addresses and DCB's are in contiguous memory. 139 */ 140 u32 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 } 146 EXPORT_SYMBOL_GPL(fdma_get_size_contiguous); 147