1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Copyright(c) 2016-2018 Intel Corporation. All rights reserved. 4 */ 5 #include <linux/dma-mapping.h> 6 #include <linux/mei.h> 7 8 #include "mei_dev.h" 9 10 /** 11 * mei_dmam_dscr_alloc() - allocate a managed coherent buffer 12 * for the dma descriptor 13 * @dev: mei_device 14 * @dscr: dma descriptor 15 * 16 * Return: 17 * * 0 - on success or zero allocation request 18 * * -EINVAL - if size is not power of 2 19 * * -ENOMEM - of allocation has failed 20 */ 21 static int mei_dmam_dscr_alloc(struct mei_device *dev, 22 struct mei_dma_dscr *dscr) 23 { 24 if (!dscr->size) 25 return 0; 26 27 if (WARN_ON(!is_power_of_2(dscr->size))) 28 return -EINVAL; 29 30 if (dscr->vaddr) 31 return 0; 32 33 dscr->vaddr = dmam_alloc_coherent(dev->dev, dscr->size, &dscr->daddr, 34 GFP_KERNEL); 35 if (!dscr->vaddr) 36 return -ENOMEM; 37 38 return 0; 39 } 40 41 /** 42 * mei_dmam_dscr_free() - free a managed coherent buffer 43 * from the dma descriptor 44 * @dev: mei_device 45 * @dscr: dma descriptor 46 */ 47 static void mei_dmam_dscr_free(struct mei_device *dev, 48 struct mei_dma_dscr *dscr) 49 { 50 if (!dscr->vaddr) 51 return; 52 53 dmam_free_coherent(dev->dev, dscr->size, dscr->vaddr, dscr->daddr); 54 dscr->vaddr = NULL; 55 } 56 57 /** 58 * mei_dmam_ring_free() - free dma ring buffers 59 * @dev: mei device 60 */ 61 void mei_dmam_ring_free(struct mei_device *dev) 62 { 63 int i; 64 65 for (i = 0; i < DMA_DSCR_NUM; i++) 66 mei_dmam_dscr_free(dev, &dev->dr_dscr[i]); 67 } 68 69 /** 70 * mei_dmam_ring_alloc() - allocate dma ring buffers 71 * @dev: mei device 72 * 73 * Return: -ENOMEM on allocation failure 0 otherwise 74 */ 75 int mei_dmam_ring_alloc(struct mei_device *dev) 76 { 77 int i; 78 79 for (i = 0; i < DMA_DSCR_NUM; i++) 80 if (mei_dmam_dscr_alloc(dev, &dev->dr_dscr[i])) 81 goto err; 82 83 return 0; 84 85 err: 86 mei_dmam_ring_free(dev); 87 return -ENOMEM; 88 } 89 90 /** 91 * mei_dma_ring_is_allocated() - check if dma ring is allocated 92 * @dev: mei device 93 * 94 * Return: true if dma ring is allocated 95 */ 96 bool mei_dma_ring_is_allocated(struct mei_device *dev) 97 { 98 return !!dev->dr_dscr[DMA_DSCR_HOST].vaddr; 99 } 100 101 static inline 102 struct hbm_dma_ring_ctrl *mei_dma_ring_ctrl(struct mei_device *dev) 103 { 104 return (struct hbm_dma_ring_ctrl *)dev->dr_dscr[DMA_DSCR_CTRL].vaddr; 105 } 106 107 /** 108 * mei_dma_ring_reset() - reset the dma control block 109 * @dev: mei device 110 */ 111 void mei_dma_ring_reset(struct mei_device *dev) 112 { 113 struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 114 115 if (!ctrl) 116 return; 117 118 memset(ctrl, 0, sizeof(*ctrl)); 119 } 120 121 /** 122 * mei_dma_copy_from() - copy from dma ring into buffer 123 * @dev: mei device 124 * @buf: data buffer 125 * @offset: offset in slots. 126 * @n: number of slots to copy. 127 */ 128 static size_t mei_dma_copy_from(struct mei_device *dev, unsigned char *buf, 129 u32 offset, u32 n) 130 { 131 unsigned char *dbuf = dev->dr_dscr[DMA_DSCR_DEVICE].vaddr; 132 133 size_t b_offset = offset << 2; 134 size_t b_n = n << 2; 135 136 memcpy(buf, dbuf + b_offset, b_n); 137 138 return b_n; 139 } 140 141 /** 142 * mei_dma_copy_to() - copy to a buffer to the dma ring 143 * @dev: mei device 144 * @buf: data buffer 145 * @offset: offset in slots. 146 * @n: number of slots to copy. 147 */ 148 static size_t mei_dma_copy_to(struct mei_device *dev, unsigned char *buf, 149 u32 offset, u32 n) 150 { 151 unsigned char *hbuf = dev->dr_dscr[DMA_DSCR_HOST].vaddr; 152 153 size_t b_offset = offset << 2; 154 size_t b_n = n << 2; 155 156 memcpy(hbuf + b_offset, buf, b_n); 157 158 return b_n; 159 } 160 161 /** 162 * mei_dma_ring_read() - read data from the ring 163 * @dev: mei device 164 * @buf: buffer to read into: may be NULL in case of droping the data. 165 * @len: length to read. 166 */ 167 void mei_dma_ring_read(struct mei_device *dev, unsigned char *buf, u32 len) 168 { 169 struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 170 u32 dbuf_depth; 171 u32 rd_idx, rem, slots; 172 173 if (WARN_ON(!ctrl)) 174 return; 175 176 dev_dbg(dev->dev, "reading from dma %u bytes\n", len); 177 178 if (!len) 179 return; 180 181 dbuf_depth = dev->dr_dscr[DMA_DSCR_DEVICE].size >> 2; 182 rd_idx = READ_ONCE(ctrl->dbuf_rd_idx) & (dbuf_depth - 1); 183 slots = mei_data2slots(len); 184 185 /* if buf is NULL we drop the packet by advancing the pointer.*/ 186 if (!buf) 187 goto out; 188 189 if (rd_idx + slots > dbuf_depth) { 190 buf += mei_dma_copy_from(dev, buf, rd_idx, dbuf_depth - rd_idx); 191 rem = slots - (dbuf_depth - rd_idx); 192 rd_idx = 0; 193 } else { 194 rem = slots; 195 } 196 197 mei_dma_copy_from(dev, buf, rd_idx, rem); 198 out: 199 WRITE_ONCE(ctrl->dbuf_rd_idx, ctrl->dbuf_rd_idx + slots); 200 } 201 202 static inline u32 mei_dma_ring_hbuf_depth(struct mei_device *dev) 203 { 204 return dev->dr_dscr[DMA_DSCR_HOST].size >> 2; 205 } 206 207 /** 208 * mei_dma_ring_empty_slots() - calaculate number of empty slots in dma ring 209 * @dev: mei_device 210 * 211 * Return: number of empty slots 212 */ 213 u32 mei_dma_ring_empty_slots(struct mei_device *dev) 214 { 215 struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 216 u32 wr_idx, rd_idx, hbuf_depth, empty; 217 218 if (!mei_dma_ring_is_allocated(dev)) 219 return 0; 220 221 if (WARN_ON(!ctrl)) 222 return 0; 223 224 /* easier to work in slots */ 225 hbuf_depth = mei_dma_ring_hbuf_depth(dev); 226 rd_idx = READ_ONCE(ctrl->hbuf_rd_idx); 227 wr_idx = READ_ONCE(ctrl->hbuf_wr_idx); 228 229 if (rd_idx > wr_idx) 230 empty = rd_idx - wr_idx; 231 else 232 empty = hbuf_depth - (wr_idx - rd_idx); 233 234 return empty; 235 } 236 237 /** 238 * mei_dma_ring_write - write data to dma ring host buffer 239 * 240 * @dev: mei_device 241 * @buf: data will be written 242 * @len: data length 243 */ 244 void mei_dma_ring_write(struct mei_device *dev, unsigned char *buf, u32 len) 245 { 246 struct hbm_dma_ring_ctrl *ctrl = mei_dma_ring_ctrl(dev); 247 u32 hbuf_depth; 248 u32 wr_idx, rem, slots; 249 250 if (WARN_ON(!ctrl)) 251 return; 252 253 dev_dbg(dev->dev, "writing to dma %u bytes\n", len); 254 hbuf_depth = mei_dma_ring_hbuf_depth(dev); 255 wr_idx = READ_ONCE(ctrl->hbuf_wr_idx) & (hbuf_depth - 1); 256 slots = mei_data2slots(len); 257 258 if (wr_idx + slots > hbuf_depth) { 259 buf += mei_dma_copy_to(dev, buf, wr_idx, hbuf_depth - wr_idx); 260 rem = slots - (hbuf_depth - wr_idx); 261 wr_idx = 0; 262 } else { 263 rem = slots; 264 } 265 266 mei_dma_copy_to(dev, buf, wr_idx, rem); 267 268 WRITE_ONCE(ctrl->hbuf_wr_idx, ctrl->hbuf_wr_idx + slots); 269 } 270