Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2024 Marvell.
3 : : */
4 : :
5 : : #include <string.h>
6 : :
7 : : #include <bus_pci_driver.h>
8 : : #include <rte_bus_pci.h>
9 : : #include <rte_common.h>
10 : : #include <rte_dmadev.h>
11 : : #include <rte_dmadev_pmd.h>
12 : : #include <rte_memcpy.h>
13 : : #include <rte_pci.h>
14 : :
15 : : #include "odm.h"
16 : :
17 : : #define PCI_VENDOR_ID_CAVIUM 0x177D
18 : : #define PCI_DEVID_ODYSSEY_ODM_VF 0xA08C
19 : : #define PCI_DRIVER_NAME dma_odm
20 : :
21 : : static int
22 : 0 : odm_dmadev_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *dev_info, uint32_t size)
23 : : {
24 : : struct odm_dev *odm = NULL;
25 : :
26 : : RTE_SET_USED(size);
27 : :
28 : 0 : odm = dev->fp_obj->dev_private;
29 : :
30 : 0 : dev_info->max_vchans = odm->max_qs;
31 : 0 : dev_info->nb_vchans = odm->num_qs;
32 : 0 : dev_info->dev_capa =
33 : : (RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_OPS_COPY | RTE_DMA_CAPA_OPS_COPY_SG |
34 : : RTE_DMA_CAPA_MEM_TO_DEV | RTE_DMA_CAPA_DEV_TO_MEM);
35 : 0 : dev_info->max_desc = ODM_IRING_MAX_ENTRY;
36 : 0 : dev_info->min_desc = 1;
37 : 0 : dev_info->max_sges = ODM_MAX_POINTER;
38 : :
39 : 0 : return 0;
40 : : }
41 : :
42 : : static int
43 : 0 : odm_dmadev_configure(struct rte_dma_dev *dev, const struct rte_dma_conf *conf, uint32_t conf_sz)
44 : : {
45 : : struct odm_dev *odm = NULL;
46 : :
47 : : RTE_SET_USED(conf_sz);
48 : :
49 : 0 : odm = dev->fp_obj->dev_private;
50 : 0 : odm->num_qs = conf->nb_vchans;
51 : :
52 : 0 : return 0;
53 : : }
54 : :
55 : : static int
56 : 0 : odm_dmadev_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan,
57 : : const struct rte_dma_vchan_conf *conf, uint32_t conf_sz)
58 : : {
59 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
60 : :
61 : : RTE_SET_USED(conf_sz);
62 : 0 : return odm_vchan_setup(odm, vchan, conf);
63 : : }
64 : :
65 : : static int
66 : 0 : odm_dmadev_start(struct rte_dma_dev *dev)
67 : : {
68 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
69 : :
70 : 0 : return odm_enable(odm);
71 : : }
72 : :
73 : : static int
74 : 0 : odm_dmadev_stop(struct rte_dma_dev *dev)
75 : : {
76 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
77 : :
78 : 0 : return odm_disable(odm);
79 : : }
80 : :
81 : : static int
82 : 0 : odm_dmadev_close(struct rte_dma_dev *dev)
83 : : {
84 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
85 : :
86 : 0 : odm_disable(odm);
87 : 0 : odm_dev_fini(odm);
88 : :
89 : 0 : return 0;
90 : : }
91 : :
92 : : static int
93 : 0 : odm_dmadev_copy(void *dev_private, uint16_t vchan, rte_iova_t src, rte_iova_t dst, uint32_t length,
94 : : uint64_t flags)
95 : : {
96 : : uint16_t pending_submit_len, pending_submit_cnt, iring_sz_available, iring_head;
97 : : const int num_words = ODM_IRING_ENTRY_SIZE_MIN;
98 : : struct odm_dev *odm = dev_private;
99 : : uint64_t *iring_head_ptr;
100 : : struct odm_queue *vq;
101 : : uint64_t h;
102 : :
103 : 0 : union odm_instr_hdr_s hdr = {
104 : : .s.ct = ODM_HDR_CT_CW_NC,
105 : : .s.xtype = ODM_XTYPE_INTERNAL,
106 : : .s.nfst = 1,
107 : : .s.nlst = 1,
108 : : };
109 : :
110 : 0 : vq = &odm->vq[vchan];
111 : 0 : hdr.s.xtype = vq->xtype;
112 : :
113 [ # # ]: 0 : if (unlikely(!length))
114 : : return -EINVAL;
115 : :
116 : 0 : h = length;
117 : 0 : h |= ((uint64_t)length << 32);
118 : :
119 : 0 : const uint16_t max_iring_words = vq->iring_max_words;
120 : :
121 : 0 : iring_sz_available = vq->iring_sz_available;
122 : 0 : pending_submit_len = vq->pending_submit_len;
123 : 0 : pending_submit_cnt = vq->pending_submit_cnt;
124 : 0 : iring_head_ptr = vq->iring_mz->addr;
125 : 0 : iring_head = vq->iring_head;
126 : :
127 [ # # ]: 0 : if (iring_sz_available < num_words)
128 : : return -ENOSPC;
129 : :
130 [ # # ]: 0 : if ((iring_head + num_words) >= max_iring_words) {
131 : :
132 : 0 : iring_head_ptr[iring_head] = hdr.u;
133 : 0 : iring_head = (iring_head + 1) % max_iring_words;
134 : :
135 : 0 : iring_head_ptr[iring_head] = h;
136 : 0 : iring_head = (iring_head + 1) % max_iring_words;
137 : :
138 : 0 : iring_head_ptr[iring_head] = src;
139 : 0 : iring_head = (iring_head + 1) % max_iring_words;
140 : :
141 : 0 : iring_head_ptr[iring_head] = dst;
142 : 0 : iring_head = (iring_head + 1) % max_iring_words;
143 : : } else {
144 : 0 : iring_head_ptr[iring_head++] = hdr.u;
145 : 0 : iring_head_ptr[iring_head++] = h;
146 : 0 : iring_head_ptr[iring_head++] = src;
147 : 0 : iring_head_ptr[iring_head++] = dst;
148 : : }
149 : :
150 : 0 : pending_submit_len += num_words;
151 : :
152 [ # # ]: 0 : if (flags & RTE_DMA_OP_FLAG_SUBMIT) {
153 : : rte_wmb();
154 : 0 : odm_write64(pending_submit_len, odm->rbase + ODM_VDMA_DBELL(vchan));
155 : 0 : vq->stats.submitted += pending_submit_cnt + 1;
156 : 0 : vq->pending_submit_len = 0;
157 : 0 : vq->pending_submit_cnt = 0;
158 : : } else {
159 : 0 : vq->pending_submit_len = pending_submit_len;
160 : 0 : vq->pending_submit_cnt++;
161 : : }
162 : :
163 : 0 : vq->iring_head = iring_head;
164 : :
165 : 0 : vq->iring_sz_available = iring_sz_available - num_words;
166 : :
167 : : /* No extra space to save. Skip entry in extra space ring. */
168 : 0 : vq->ins_ring_head = (vq->ins_ring_head + 1) % vq->cring_max_entry;
169 : :
170 : 0 : return vq->desc_idx++;
171 : : }
172 : :
173 : : static inline void
174 : 0 : odm_dmadev_fill_sg(uint64_t *cmd, const struct rte_dma_sge *src, const struct rte_dma_sge *dst,
175 : : uint16_t nb_src, uint16_t nb_dst, union odm_instr_hdr_s *hdr)
176 : : {
177 : : int i = 0, j = 0;
178 : : uint64_t h = 0;
179 : :
180 : 0 : cmd[j++] = hdr->u;
181 : : /* When nb_src is even */
182 [ # # ]: 0 : if (!(nb_src & 0x1)) {
183 : : /* Fill the iring with src pointers */
184 [ # # ]: 0 : for (i = 1; i < nb_src; i += 2) {
185 : 0 : h = ((uint64_t)src[i].length << 32) | src[i - 1].length;
186 : 0 : cmd[j++] = h;
187 : 0 : cmd[j++] = src[i - 1].addr;
188 : 0 : cmd[j++] = src[i].addr;
189 : : }
190 : :
191 : : /* Fill the iring with dst pointers */
192 [ # # ]: 0 : for (i = 1; i < nb_dst; i += 2) {
193 : 0 : h = ((uint64_t)dst[i].length << 32) | dst[i - 1].length;
194 : 0 : cmd[j++] = h;
195 : 0 : cmd[j++] = dst[i - 1].addr;
196 : 0 : cmd[j++] = dst[i].addr;
197 : : }
198 : :
199 : : /* Handle the last dst pointer when nb_dst is odd */
200 [ # # ]: 0 : if (nb_dst & 0x1) {
201 : 0 : h = dst[nb_dst - 1].length;
202 : 0 : cmd[j++] = h;
203 : 0 : cmd[j++] = dst[nb_dst - 1].addr;
204 : 0 : cmd[j++] = 0;
205 : : }
206 : : } else {
207 : : /* When nb_src is odd */
208 : :
209 : : /* Fill the iring with src pointers */
210 [ # # ]: 0 : for (i = 1; i < nb_src; i += 2) {
211 : 0 : h = ((uint64_t)src[i].length << 32) | src[i - 1].length;
212 : 0 : cmd[j++] = h;
213 : 0 : cmd[j++] = src[i - 1].addr;
214 : 0 : cmd[j++] = src[i].addr;
215 : : }
216 : :
217 : : /* Handle the last src pointer */
218 : 0 : h = ((uint64_t)dst[0].length << 32) | src[nb_src - 1].length;
219 : 0 : cmd[j++] = h;
220 : 0 : cmd[j++] = src[nb_src - 1].addr;
221 : 0 : cmd[j++] = dst[0].addr;
222 : :
223 : : /* Fill the iring with dst pointers */
224 [ # # ]: 0 : for (i = 2; i < nb_dst; i += 2) {
225 : 0 : h = ((uint64_t)dst[i].length << 32) | dst[i - 1].length;
226 : 0 : cmd[j++] = h;
227 : 0 : cmd[j++] = dst[i - 1].addr;
228 : 0 : cmd[j++] = dst[i].addr;
229 : : }
230 : :
231 : : /* Handle the last dst pointer when nb_dst is even */
232 [ # # ]: 0 : if (!(nb_dst & 0x1)) {
233 : 0 : h = dst[nb_dst - 1].length;
234 : 0 : cmd[j++] = h;
235 : 0 : cmd[j++] = dst[nb_dst - 1].addr;
236 : 0 : cmd[j++] = 0;
237 : : }
238 : : }
239 : 0 : }
240 : :
241 : : static int
242 : 0 : odm_dmadev_copy_sg(void *dev_private, uint16_t vchan, const struct rte_dma_sge *src,
243 : : const struct rte_dma_sge *dst, uint16_t nb_src, uint16_t nb_dst, uint64_t flags)
244 : : {
245 : : uint16_t pending_submit_len, pending_submit_cnt, iring_head, ins_ring_head;
246 : : uint16_t iring_sz_available, i, nb, num_words;
247 : : uint64_t cmd[ODM_IRING_ENTRY_SIZE_MAX];
248 : : struct odm_dev *odm = dev_private;
249 : : uint32_t s_sz = 0, d_sz = 0;
250 : : uint64_t *iring_head_ptr;
251 : : struct odm_queue *vq;
252 : 0 : union odm_instr_hdr_s hdr = {
253 : : .s.ct = ODM_HDR_CT_CW_NC,
254 : : .s.xtype = ODM_XTYPE_INTERNAL,
255 : : };
256 : :
257 : 0 : vq = &odm->vq[vchan];
258 : 0 : const uint16_t max_iring_words = vq->iring_max_words;
259 : :
260 : 0 : hdr.s.xtype = vq->xtype;
261 : 0 : iring_head_ptr = vq->iring_mz->addr;
262 : 0 : iring_head = vq->iring_head;
263 : 0 : iring_sz_available = vq->iring_sz_available;
264 : 0 : ins_ring_head = vq->ins_ring_head;
265 : 0 : pending_submit_len = vq->pending_submit_len;
266 : 0 : pending_submit_cnt = vq->pending_submit_cnt;
267 : :
268 [ # # # # ]: 0 : if (unlikely(!nb_src || nb_src > 4 || !nb_dst || nb_dst > 4))
269 : : return -EINVAL;
270 : :
271 [ # # ]: 0 : for (i = 0; i < nb_src; i++) {
272 [ # # ]: 0 : if (unlikely(!src[i].length))
273 : : return -EINVAL;
274 : 0 : s_sz += src[i].length;
275 : : }
276 : :
277 [ # # ]: 0 : for (i = 0; i < nb_dst; i++) {
278 [ # # ]: 0 : if (unlikely(!dst[i].length))
279 : : return -EINVAL;
280 : 0 : d_sz += dst[i].length;
281 : : }
282 : :
283 [ # # ]: 0 : if (s_sz != d_sz)
284 : : return -EINVAL;
285 : :
286 : 0 : nb = nb_src + nb_dst;
287 : 0 : hdr.s.nfst = nb_src;
288 : 0 : hdr.s.nlst = nb_dst;
289 : 0 : num_words = 1 + 3 * (nb / 2 + (nb & 0x1));
290 : :
291 [ # # ]: 0 : if (iring_sz_available < num_words)
292 : : return -ENOSPC;
293 : :
294 [ # # ]: 0 : if ((iring_head + num_words) >= max_iring_words) {
295 : 0 : uint16_t words_avail = max_iring_words - iring_head;
296 : 0 : uint16_t words_pend = num_words - words_avail;
297 : :
298 [ # # ]: 0 : if (unlikely(words_avail + words_pend > ODM_IRING_ENTRY_SIZE_MAX))
299 : : return -ENOSPC;
300 : :
301 : 0 : odm_dmadev_fill_sg(cmd, src, dst, nb_src, nb_dst, &hdr);
302 [ # # ]: 0 : rte_memcpy((void *)&iring_head_ptr[iring_head], (void *)cmd, words_avail * 8);
303 [ # # ]: 0 : rte_memcpy((void *)iring_head_ptr, (void *)&cmd[words_avail], words_pend * 8);
304 : : iring_head = words_pend;
305 : : } else {
306 : 0 : odm_dmadev_fill_sg(&iring_head_ptr[iring_head], src, dst, nb_src, nb_dst, &hdr);
307 : 0 : iring_head += num_words;
308 : : }
309 : :
310 : 0 : pending_submit_len += num_words;
311 : :
312 [ # # ]: 0 : if (flags & RTE_DMA_OP_FLAG_SUBMIT) {
313 : : rte_wmb();
314 : 0 : odm_write64(pending_submit_len, odm->rbase + ODM_VDMA_DBELL(vchan));
315 : 0 : vq->stats.submitted += pending_submit_cnt + 1;
316 : 0 : vq->pending_submit_len = 0;
317 : 0 : vq->pending_submit_cnt = 0;
318 : : } else {
319 : 0 : vq->pending_submit_len = pending_submit_len;
320 : 0 : vq->pending_submit_cnt++;
321 : : }
322 : :
323 : 0 : vq->iring_head = iring_head;
324 : :
325 : 0 : vq->iring_sz_available = iring_sz_available - num_words;
326 : :
327 : : /* Save extra space used for the instruction. */
328 : 0 : vq->extra_ins_sz[ins_ring_head] = num_words - 4;
329 : :
330 : 0 : vq->ins_ring_head = (ins_ring_head + 1) % vq->cring_max_entry;
331 : :
332 : 0 : return vq->desc_idx++;
333 : : }
334 : :
335 : : static int
336 : 0 : odm_dmadev_fill(void *dev_private, uint16_t vchan, uint64_t pattern, rte_iova_t dst,
337 : : uint32_t length, uint64_t flags)
338 : : {
339 : : uint16_t pending_submit_len, pending_submit_cnt, iring_sz_available, iring_head;
340 : : const int num_words = ODM_IRING_ENTRY_SIZE_MIN;
341 : : struct odm_dev *odm = dev_private;
342 : : uint64_t *iring_head_ptr;
343 : : struct odm_queue *vq;
344 : : uint64_t h;
345 : :
346 : 0 : vq = &odm->vq[vchan];
347 : :
348 : 0 : union odm_instr_hdr_s hdr = {
349 : : .s.ct = ODM_HDR_CT_CW_NC,
350 : : .s.nfst = 0,
351 : : .s.nlst = 1,
352 : : };
353 : :
354 [ # # ]: 0 : if (unlikely(!length))
355 : : return -EINVAL;
356 : :
357 : 0 : h = (uint64_t)length;
358 : :
359 [ # # # ]: 0 : switch (pattern) {
360 : 0 : case 0:
361 : 0 : hdr.s.xtype = ODM_XTYPE_FILL0;
362 : 0 : break;
363 : 0 : case 0xffffffffffffffff:
364 : 0 : hdr.s.xtype = ODM_XTYPE_FILL1;
365 : 0 : break;
366 : : default:
367 : : return -ENOTSUP;
368 : : }
369 : :
370 : 0 : const uint16_t max_iring_words = vq->iring_max_words;
371 : :
372 : 0 : iring_sz_available = vq->iring_sz_available;
373 : 0 : pending_submit_len = vq->pending_submit_len;
374 : 0 : pending_submit_cnt = vq->pending_submit_cnt;
375 : 0 : iring_head_ptr = vq->iring_mz->addr;
376 : 0 : iring_head = vq->iring_head;
377 : :
378 [ # # ]: 0 : if (iring_sz_available < num_words)
379 : : return -ENOSPC;
380 : :
381 [ # # ]: 0 : if ((iring_head + num_words) >= max_iring_words) {
382 : :
383 : 0 : iring_head_ptr[iring_head] = hdr.u;
384 : 0 : iring_head = (iring_head + 1) % max_iring_words;
385 : :
386 : 0 : iring_head_ptr[iring_head] = h;
387 : 0 : iring_head = (iring_head + 1) % max_iring_words;
388 : :
389 : 0 : iring_head_ptr[iring_head] = dst;
390 : 0 : iring_head = (iring_head + 1) % max_iring_words;
391 : :
392 : 0 : iring_head_ptr[iring_head] = 0;
393 : 0 : iring_head = (iring_head + 1) % max_iring_words;
394 : : } else {
395 : 0 : iring_head_ptr[iring_head] = hdr.u;
396 : 0 : iring_head_ptr[iring_head + 1] = h;
397 : 0 : iring_head_ptr[iring_head + 2] = dst;
398 : 0 : iring_head_ptr[iring_head + 3] = 0;
399 : 0 : iring_head += num_words;
400 : : }
401 : :
402 : 0 : pending_submit_len += num_words;
403 : :
404 [ # # ]: 0 : if (flags & RTE_DMA_OP_FLAG_SUBMIT) {
405 : : rte_wmb();
406 : 0 : odm_write64(pending_submit_len, odm->rbase + ODM_VDMA_DBELL(vchan));
407 : 0 : vq->stats.submitted += pending_submit_cnt + 1;
408 : 0 : vq->pending_submit_len = 0;
409 : 0 : vq->pending_submit_cnt = 0;
410 : : } else {
411 : 0 : vq->pending_submit_len = pending_submit_len;
412 : 0 : vq->pending_submit_cnt++;
413 : : }
414 : :
415 : 0 : vq->iring_head = iring_head;
416 : 0 : vq->iring_sz_available = iring_sz_available - num_words;
417 : :
418 : : /* No extra space to save. Skip entry in extra space ring. */
419 : 0 : vq->ins_ring_head = (vq->ins_ring_head + 1) % vq->cring_max_entry;
420 : :
421 : : vq->iring_sz_available = iring_sz_available - num_words;
422 : :
423 : 0 : return vq->desc_idx++;
424 : : }
425 : :
426 : : static uint16_t
427 : 0 : odm_dmadev_completed(void *dev_private, uint16_t vchan, const uint16_t nb_cpls, uint16_t *last_idx,
428 : : bool *has_error)
429 : : {
430 : : const union odm_cmpl_ent_s cmpl_zero = {0};
431 : : uint16_t cring_head, iring_sz_available;
432 : : struct odm_dev *odm = dev_private;
433 : : union odm_cmpl_ent_s cmpl;
434 : : struct odm_queue *vq;
435 : : uint64_t nb_err = 0;
436 : : uint32_t *cmpl_ptr;
437 : : int cnt;
438 : :
439 : 0 : vq = &odm->vq[vchan];
440 : 0 : const uint32_t *base_addr = vq->cring_mz->addr;
441 : 0 : const uint16_t cring_max_entry = vq->cring_max_entry;
442 : :
443 : 0 : cring_head = vq->cring_head;
444 : 0 : iring_sz_available = vq->iring_sz_available;
445 : :
446 [ # # ]: 0 : if (unlikely(vq->stats.submitted == vq->stats.completed)) {
447 : 0 : *last_idx = (vq->stats.completed_offset + vq->stats.completed - 1) & 0xFFFF;
448 : 0 : return 0;
449 : : }
450 : :
451 [ # # ]: 0 : for (cnt = 0; cnt < nb_cpls; cnt++) {
452 : 0 : cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
453 : 0 : cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
454 : : rte_memory_order_relaxed);
455 [ # # ]: 0 : if (!cmpl.s.valid)
456 : : break;
457 : :
458 [ # # ]: 0 : if (cmpl.s.cmp_code)
459 : 0 : nb_err++;
460 : :
461 : : /* Free space for enqueue */
462 : 0 : iring_sz_available += 4 + vq->extra_ins_sz[cring_head];
463 : :
464 : : /* Clear instruction extra space */
465 : 0 : vq->extra_ins_sz[cring_head] = 0;
466 : :
467 : 0 : rte_atomic_store_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr, cmpl_zero.u,
468 : : rte_memory_order_relaxed);
469 : 0 : cring_head = (cring_head + 1) % cring_max_entry;
470 : : }
471 : :
472 : 0 : vq->stats.errors += nb_err;
473 : :
474 [ # # ]: 0 : if (unlikely(has_error != NULL && nb_err))
475 : 0 : *has_error = true;
476 : :
477 : 0 : vq->cring_head = cring_head;
478 : 0 : vq->iring_sz_available = iring_sz_available;
479 : :
480 : 0 : vq->stats.completed += cnt;
481 : :
482 : 0 : *last_idx = (vq->stats.completed_offset + vq->stats.completed - 1) & 0xFFFF;
483 : :
484 : 0 : return cnt;
485 : : }
486 : :
487 : : static uint16_t
488 : 0 : odm_dmadev_completed_status(void *dev_private, uint16_t vchan, const uint16_t nb_cpls,
489 : : uint16_t *last_idx, enum rte_dma_status_code *status)
490 : : {
491 : : const union odm_cmpl_ent_s cmpl_zero = {0};
492 : : uint16_t cring_head, iring_sz_available;
493 : : struct odm_dev *odm = dev_private;
494 : : union odm_cmpl_ent_s cmpl;
495 : : struct odm_queue *vq;
496 : : uint32_t *cmpl_ptr;
497 : : int cnt;
498 : :
499 : 0 : vq = &odm->vq[vchan];
500 : 0 : const uint32_t *base_addr = vq->cring_mz->addr;
501 : 0 : const uint16_t cring_max_entry = vq->cring_max_entry;
502 : :
503 : 0 : cring_head = vq->cring_head;
504 : 0 : iring_sz_available = vq->iring_sz_available;
505 : :
506 [ # # ]: 0 : if (vq->stats.submitted == vq->stats.completed) {
507 : 0 : *last_idx = (vq->stats.completed_offset + vq->stats.completed - 1) & 0xFFFF;
508 : 0 : return 0;
509 : : }
510 : :
511 : : #ifdef ODM_DEBUG
512 : : ODM_LOG(DEBUG, "cring_head: 0x%" PRIx16, cring_head);
513 : : ODM_LOG(DEBUG, "Submitted: 0x%" PRIx64, vq->stats.submitted);
514 : : ODM_LOG(DEBUG, "Completed: 0x%" PRIx64, vq->stats.completed);
515 : : ODM_LOG(DEBUG, "Hardware count: 0x%" PRIx64, odm_read64(odm->rbase + ODM_VDMA_CNT(vchan)));
516 : : #endif
517 : :
518 [ # # ]: 0 : for (cnt = 0; cnt < nb_cpls; cnt++) {
519 : 0 : cmpl_ptr = RTE_PTR_ADD(base_addr, cring_head * sizeof(cmpl));
520 : 0 : cmpl.u = rte_atomic_load_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr,
521 : : rte_memory_order_relaxed);
522 [ # # ]: 0 : if (!cmpl.s.valid)
523 : : break;
524 : :
525 : 0 : status[cnt] = cmpl.s.cmp_code;
526 : :
527 [ # # ]: 0 : if (cmpl.s.cmp_code)
528 : 0 : vq->stats.errors++;
529 : :
530 : : /* Free space for enqueue */
531 : 0 : iring_sz_available += 4 + vq->extra_ins_sz[cring_head];
532 : :
533 : : /* Clear instruction extra space */
534 : 0 : vq->extra_ins_sz[cring_head] = 0;
535 : :
536 : 0 : rte_atomic_store_explicit((RTE_ATOMIC(uint32_t) *)cmpl_ptr, cmpl_zero.u,
537 : : rte_memory_order_relaxed);
538 : 0 : cring_head = (cring_head + 1) % cring_max_entry;
539 : : }
540 : :
541 : 0 : vq->cring_head = cring_head;
542 : 0 : vq->iring_sz_available = iring_sz_available;
543 : :
544 : 0 : vq->stats.completed += cnt;
545 : :
546 : 0 : *last_idx = (vq->stats.completed_offset + vq->stats.completed - 1) & 0xFFFF;
547 : :
548 : 0 : return cnt;
549 : : }
550 : :
551 : : static int
552 : 0 : odm_dmadev_submit(void *dev_private, uint16_t vchan)
553 : : {
554 : : struct odm_dev *odm = dev_private;
555 : : uint16_t pending_submit_len;
556 : : struct odm_queue *vq;
557 : :
558 : 0 : vq = &odm->vq[vchan];
559 : 0 : pending_submit_len = vq->pending_submit_len;
560 : :
561 [ # # ]: 0 : if (pending_submit_len == 0)
562 : : return 0;
563 : :
564 : : rte_wmb();
565 : 0 : odm_write64(pending_submit_len, odm->rbase + ODM_VDMA_DBELL(vchan));
566 : 0 : vq->pending_submit_len = 0;
567 : 0 : vq->stats.submitted += vq->pending_submit_cnt;
568 : 0 : vq->pending_submit_cnt = 0;
569 : :
570 : 0 : return 0;
571 : : }
572 : :
573 : : static uint16_t
574 : 0 : odm_dmadev_burst_capacity(const void *dev_private, uint16_t vchan __rte_unused)
575 : : {
576 : : const struct odm_dev *odm = dev_private;
577 : : const struct odm_queue *vq;
578 : :
579 : 0 : vq = &odm->vq[vchan];
580 : 0 : return (vq->iring_sz_available / ODM_IRING_ENTRY_SIZE_MIN);
581 : : }
582 : :
583 : : static int
584 : 0 : odm_stats_get(const struct rte_dma_dev *dev, uint16_t vchan, struct rte_dma_stats *rte_stats,
585 : : uint32_t size)
586 : : {
587 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
588 : :
589 [ # # ]: 0 : if (size < sizeof(rte_stats))
590 : : return -EINVAL;
591 [ # # ]: 0 : if (rte_stats == NULL)
592 : : return -EINVAL;
593 : :
594 [ # # ]: 0 : if (vchan != RTE_DMA_ALL_VCHAN) {
595 : 0 : struct rte_dma_stats *stats = (struct rte_dma_stats *)&odm->vq[vchan].stats;
596 : :
597 : 0 : *rte_stats = *stats;
598 : : } else {
599 : : int i;
600 : :
601 [ # # ]: 0 : for (i = 0; i < odm->num_qs; i++) {
602 : 0 : struct rte_dma_stats *stats = (struct rte_dma_stats *)&odm->vq[i].stats;
603 : :
604 : 0 : rte_stats->submitted += stats->submitted;
605 : 0 : rte_stats->completed += stats->completed;
606 : 0 : rte_stats->errors += stats->errors;
607 : : }
608 : : }
609 : :
610 : : return 0;
611 : : }
612 : :
613 : : static void
614 : : odm_vq_stats_reset(struct vq_stats *vq_stats)
615 : : {
616 : 0 : vq_stats->completed_offset += vq_stats->completed;
617 : 0 : vq_stats->completed = 0;
618 : 0 : vq_stats->errors = 0;
619 : 0 : vq_stats->submitted = 0;
620 : 0 : }
621 : :
622 : : static int
623 : 0 : odm_stats_reset(struct rte_dma_dev *dev, uint16_t vchan)
624 : : {
625 : 0 : struct odm_dev *odm = dev->fp_obj->dev_private;
626 : : struct vq_stats *vq_stats;
627 : : int i;
628 : :
629 [ # # ]: 0 : if (vchan != RTE_DMA_ALL_VCHAN) {
630 : 0 : vq_stats = &odm->vq[vchan].stats;
631 : : odm_vq_stats_reset(vq_stats);
632 : : } else {
633 [ # # ]: 0 : for (i = 0; i < odm->num_qs; i++) {
634 : : vq_stats = &odm->vq[i].stats;
635 : : odm_vq_stats_reset(vq_stats);
636 : : }
637 : : }
638 : :
639 : 0 : return 0;
640 : : }
641 : :
642 : : static const struct rte_dma_dev_ops odm_dmadev_ops = {
643 : : .dev_close = odm_dmadev_close,
644 : : .dev_configure = odm_dmadev_configure,
645 : : .dev_info_get = odm_dmadev_info_get,
646 : : .dev_start = odm_dmadev_start,
647 : : .dev_stop = odm_dmadev_stop,
648 : : .stats_get = odm_stats_get,
649 : : .stats_reset = odm_stats_reset,
650 : : .vchan_setup = odm_dmadev_vchan_setup,
651 : : };
652 : :
653 : : static int
654 : 0 : odm_dmadev_probe(struct rte_pci_driver *pci_drv __rte_unused, struct rte_pci_device *pci_dev)
655 : : {
656 : : char name[RTE_DEV_NAME_MAX_LEN];
657 : : struct odm_dev *odm = NULL;
658 : : struct rte_dma_dev *dmadev;
659 : : int rc;
660 : :
661 [ # # ]: 0 : if (!pci_dev->mem_resource[0].addr)
662 : : return -ENODEV;
663 : :
664 : : memset(name, 0, sizeof(name));
665 : 0 : rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
666 : :
667 : 0 : dmadev = rte_dma_pmd_allocate(name, pci_dev->device.numa_node, sizeof(*odm));
668 [ # # ]: 0 : if (dmadev == NULL) {
669 : 0 : ODM_LOG(ERR, "DMA device allocation failed for %s", name);
670 : 0 : return -ENOMEM;
671 : : }
672 : :
673 : 0 : ODM_LOG(INFO, "DMA device %s probed", name);
674 : 0 : odm = dmadev->data->dev_private;
675 : :
676 : 0 : dmadev->device = &pci_dev->device;
677 : 0 : dmadev->fp_obj->dev_private = odm;
678 : 0 : dmadev->dev_ops = &odm_dmadev_ops;
679 : :
680 : 0 : dmadev->fp_obj->copy = odm_dmadev_copy;
681 : 0 : dmadev->fp_obj->copy_sg = odm_dmadev_copy_sg;
682 : 0 : dmadev->fp_obj->fill = odm_dmadev_fill;
683 : 0 : dmadev->fp_obj->submit = odm_dmadev_submit;
684 : 0 : dmadev->fp_obj->completed = odm_dmadev_completed;
685 : 0 : dmadev->fp_obj->completed_status = odm_dmadev_completed_status;
686 : 0 : dmadev->fp_obj->burst_capacity = odm_dmadev_burst_capacity;
687 : :
688 : 0 : odm->pci_dev = pci_dev;
689 : :
690 : 0 : rc = odm_dev_init(odm);
691 [ # # ]: 0 : if (rc < 0)
692 : 0 : goto dma_pmd_release;
693 : :
694 : : return 0;
695 : :
696 : : dma_pmd_release:
697 : 0 : rte_dma_pmd_release(name);
698 : :
699 : 0 : return rc;
700 : : }
701 : :
702 : : static int
703 : 0 : odm_dmadev_remove(struct rte_pci_device *pci_dev)
704 : : {
705 : : char name[RTE_DEV_NAME_MAX_LEN];
706 : :
707 : : memset(name, 0, sizeof(name));
708 : 0 : rte_pci_device_name(&pci_dev->addr, name, sizeof(name));
709 : :
710 : 0 : return rte_dma_pmd_release(name);
711 : : }
712 : :
713 : : static const struct rte_pci_id odm_dma_pci_map[] = {
714 : : {
715 : : RTE_PCI_DEVICE(PCI_VENDOR_ID_CAVIUM, PCI_DEVID_ODYSSEY_ODM_VF)
716 : : },
717 : : {
718 : : .vendor_id = 0,
719 : : },
720 : : };
721 : :
722 : : static struct rte_pci_driver odm_dmadev = {
723 : : .id_table = odm_dma_pci_map,
724 : : .drv_flags = RTE_PCI_DRV_NEED_MAPPING,
725 : : .probe = odm_dmadev_probe,
726 : : .remove = odm_dmadev_remove,
727 : : };
728 : :
729 : 301 : RTE_PMD_REGISTER_PCI(PCI_DRIVER_NAME, odm_dmadev);
730 : : RTE_PMD_REGISTER_PCI_TABLE(PCI_DRIVER_NAME, odm_dma_pci_map);
731 : : RTE_PMD_REGISTER_KMOD_DEP(PCI_DRIVER_NAME, "vfio-pci");
732 [ - + ]: 301 : RTE_LOG_REGISTER_DEFAULT(odm_logtype, NOTICE);
|