Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright 2021 Intel Corporation
3 : : */
4 : :
5 : : #include <x86intrin.h>
6 : :
7 : : #include <rte_malloc.h>
8 : : #include <rte_common.h>
9 : : #include <rte_log.h>
10 : : #include <rte_prefetch.h>
11 : :
12 : : #include "idxd_internal.h"
13 : :
14 : : #define IDXD_PMD_NAME_STR "dmadev_idxd"
15 : :
16 : : /* systems with DSA all support AVX2 so allow our data-path functions to
17 : : * always use at least that instruction set
18 : : */
19 : : #ifndef __AVX2__
20 : : #define __use_avx2 __attribute__((target("avx2")))
21 : : #else
22 : : #define __use_avx2
23 : : #endif
24 : :
25 : : __use_avx2
26 : : static __rte_always_inline rte_iova_t
27 : : __desc_idx_to_iova(struct idxd_dmadev *idxd, uint16_t n)
28 : : {
29 : 0 : return idxd->desc_iova + (n * sizeof(struct idxd_hw_desc));
30 : : }
31 : :
32 : : __use_avx2
33 : : static __rte_always_inline void
34 : : __idxd_movdir64b(volatile void *dst, const struct idxd_hw_desc *src)
35 : : {
36 : 0 : asm volatile (".byte 0x66, 0x0f, 0x38, 0xf8, 0x02"
37 : : :
38 : : : "a" (dst), "d" (src)
39 : : : "memory");
40 : : }
41 : :
42 : : __use_avx2
43 : : static __rte_always_inline void
44 : : __submit(struct idxd_dmadev *idxd)
45 : : {
46 : 0 : rte_prefetch1(&idxd->batch_comp_ring[idxd->batch_idx_read]);
47 : :
48 [ # # # # : 0 : if (idxd->batch_size == 0)
# # ]
49 : : return;
50 : :
51 : : /* write completion to batch comp ring */
52 : 0 : rte_iova_t comp_addr = idxd->batch_iova +
53 : 0 : (idxd->batch_idx_write * sizeof(struct idxd_completion));
54 : :
55 [ # # # # : 0 : if (idxd->batch_size == 1) {
# # ]
56 : : /* submit batch directly */
57 : 0 : struct idxd_hw_desc desc =
58 : 0 : idxd->desc_ring[idxd->batch_start & idxd->desc_ring_mask];
59 : 0 : desc.completion = comp_addr;
60 : 0 : desc.op_flags |= IDXD_FLAG_REQUEST_COMPLETION;
61 : : _mm_sfence(); /* fence before writing desc to device */
62 : 0 : __idxd_movdir64b(idxd->portal, &desc);
63 : : } else {
64 : 0 : const struct idxd_hw_desc batch_desc = {
65 : : .op_flags = (idxd_op_batch << IDXD_CMD_OP_SHIFT) |
66 : : IDXD_FLAG_COMPLETION_ADDR_VALID |
67 : : IDXD_FLAG_REQUEST_COMPLETION,
68 : 0 : .desc_addr = __desc_idx_to_iova(idxd,
69 : 0 : idxd->batch_start & idxd->desc_ring_mask),
70 : : .completion = comp_addr,
71 : 0 : .size = idxd->batch_size,
72 : : };
73 : : _mm_sfence(); /* fence before writing desc to device */
74 : 0 : __idxd_movdir64b(idxd->portal, &batch_desc);
75 : : }
76 : :
77 [ # # # # : 0 : if (++idxd->batch_idx_write > idxd->max_batches)
# # ]
78 : 0 : idxd->batch_idx_write = 0;
79 : :
80 : 0 : idxd->stats.submitted += idxd->batch_size;
81 : :
82 : 0 : idxd->batch_start += idxd->batch_size;
83 : 0 : idxd->batch_size = 0;
84 : 0 : idxd->batch_idx_ring[idxd->batch_idx_write] = idxd->batch_start;
85 : 0 : _mm256_store_si256((void *)&idxd->batch_comp_ring[idxd->batch_idx_write],
86 : : _mm256_setzero_si256());
87 : : }
88 : :
89 : : __use_avx2
90 : : static __rte_always_inline int
91 : : __idxd_write_desc(struct idxd_dmadev *idxd,
92 : : const uint32_t op_flags,
93 : : const rte_iova_t src,
94 : : const rte_iova_t dst,
95 : : const uint32_t size,
96 : : const uint32_t flags)
97 : : {
98 : 0 : uint16_t mask = idxd->desc_ring_mask;
99 : 0 : uint16_t job_id = idxd->batch_start + idxd->batch_size;
100 : : /* we never wrap batches, so we only mask the start and allow start+size to overflow */
101 : 0 : uint16_t write_idx = (idxd->batch_start & mask) + idxd->batch_size;
102 : :
103 : : /* first check batch ring space then desc ring space */
104 [ # # # # ]: 0 : if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) ||
105 [ # # # # ]: 0 : idxd->batch_idx_write + 1 == idxd->batch_idx_read)
106 : : return -ENOSPC;
107 [ # # # # ]: 0 : if (((write_idx + 1) & mask) == (idxd->ids_returned & mask))
108 : : return -ENOSPC;
109 : :
110 : : /* write desc. Note: descriptors don't wrap, but the completion address does */
111 : 0 : const uint64_t op_flags64 = (uint64_t)(op_flags | IDXD_FLAG_COMPLETION_ADDR_VALID) << 32;
112 : 0 : const uint64_t comp_addr = __desc_idx_to_iova(idxd, write_idx & mask);
113 : 0 : _mm256_store_si256((void *)&idxd->desc_ring[write_idx],
114 : : _mm256_set_epi64x(dst, src, comp_addr, op_flags64));
115 : 0 : _mm256_store_si256((void *)&idxd->desc_ring[write_idx].size,
116 : : _mm256_set_epi64x(0, 0, 0, size));
117 : :
118 : 0 : idxd->batch_size++;
119 : :
120 : 0 : rte_prefetch0_write(&idxd->desc_ring[write_idx + 1]);
121 : :
122 [ # # # # ]: 0 : if (flags & RTE_DMA_OP_FLAG_SUBMIT)
123 : : __submit(idxd);
124 : :
125 : 0 : return job_id;
126 : : }
127 : :
128 : : __use_avx2
129 : : int
130 : 0 : idxd_enqueue_copy(void *dev_private, uint16_t qid __rte_unused, rte_iova_t src,
131 : : rte_iova_t dst, unsigned int length, uint64_t flags)
132 : : {
133 : : /* we can take advantage of the fact that the fence flag in dmadev and DSA are the same,
134 : : * but check it at compile time to be sure.
135 : : */
136 : : RTE_BUILD_BUG_ON(RTE_DMA_OP_FLAG_FENCE != IDXD_FLAG_FENCE);
137 : : uint32_t memmove = (idxd_op_memmove << IDXD_CMD_OP_SHIFT) |
138 [ # # ]: 0 : IDXD_FLAG_CACHE_CONTROL | (flags & IDXD_FLAG_FENCE);
139 : 0 : return __idxd_write_desc(dev_private, memmove, src, dst, length,
140 : : flags);
141 : : }
142 : :
143 : : __use_avx2
144 : : int
145 : 0 : idxd_enqueue_fill(void *dev_private, uint16_t qid __rte_unused, uint64_t pattern,
146 : : rte_iova_t dst, unsigned int length, uint64_t flags)
147 : : {
148 : : uint32_t fill = (idxd_op_fill << IDXD_CMD_OP_SHIFT) |
149 [ # # ]: 0 : IDXD_FLAG_CACHE_CONTROL | (flags & IDXD_FLAG_FENCE);
150 : 0 : return __idxd_write_desc(dev_private, fill, pattern, dst, length,
151 : : flags);
152 : : }
153 : :
154 : : __use_avx2
155 : : int
156 : 0 : idxd_submit(void *dev_private, uint16_t qid __rte_unused)
157 : : {
158 : : __submit(dev_private);
159 : 0 : return 0;
160 : : }
161 : :
162 : : __use_avx2
163 : : static enum rte_dma_status_code
164 : : get_comp_status(struct idxd_completion *c)
165 : : {
166 : 0 : uint8_t st = c->status;
167 [ # # # # : 0 : switch (st) {
# # ]
168 : : /* successful descriptors are not written back normally */
169 : : case IDXD_COMP_STATUS_INCOMPLETE:
170 : : case IDXD_COMP_STATUS_SUCCESS:
171 : : return RTE_DMA_STATUS_SUCCESSFUL;
172 : 0 : case IDXD_COMP_STATUS_PAGE_FAULT:
173 : 0 : return RTE_DMA_STATUS_PAGE_FAULT;
174 : 0 : case IDXD_COMP_STATUS_INVALID_OPCODE:
175 : 0 : return RTE_DMA_STATUS_INVALID_OPCODE;
176 : 0 : case IDXD_COMP_STATUS_INVALID_SIZE:
177 : 0 : return RTE_DMA_STATUS_INVALID_LENGTH;
178 : 0 : case IDXD_COMP_STATUS_SKIPPED:
179 : 0 : return RTE_DMA_STATUS_NOT_ATTEMPTED;
180 : 0 : default:
181 : 0 : return RTE_DMA_STATUS_ERROR_UNKNOWN;
182 : : }
183 : : }
184 : :
185 : : __use_avx2
186 : : int
187 : 0 : idxd_vchan_status(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
188 : : enum rte_dma_vchan_status *status)
189 : : {
190 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
191 [ # # ]: 0 : uint16_t last_batch_write = idxd->batch_idx_write == 0 ? idxd->max_batches :
192 : : idxd->batch_idx_write - 1;
193 : 0 : uint8_t bstatus = (idxd->batch_comp_ring[last_batch_write].status != 0);
194 : :
195 : : /* An IDXD device will always be either active or idle.
196 : : * RTE_DMA_VCHAN_HALTED_ERROR is therefore not supported by IDXD.
197 : : */
198 : 0 : *status = bstatus ? RTE_DMA_VCHAN_IDLE : RTE_DMA_VCHAN_ACTIVE;
199 : :
200 : 0 : return 0;
201 : : }
202 : :
203 : : __use_avx2
204 : : static __rte_always_inline int
205 : : batch_ok(struct idxd_dmadev *idxd, uint16_t max_ops, enum rte_dma_status_code *status)
206 : : {
207 : : uint16_t ret;
208 : : uint8_t bstatus;
209 : :
210 : 0 : if (max_ops == 0)
211 : : return 0;
212 : :
213 : : /* first check if there are any unreturned handles from last time */
214 [ # # # # ]: 0 : if (idxd->ids_avail != idxd->ids_returned) {
215 : 0 : ret = RTE_MIN((uint16_t)(idxd->ids_avail - idxd->ids_returned), max_ops);
216 : 0 : idxd->ids_returned += ret;
217 [ # # ]: 0 : if (status)
218 : 0 : memset(status, RTE_DMA_STATUS_SUCCESSFUL, ret * sizeof(*status));
219 : 0 : return ret;
220 : : }
221 : :
222 [ # # # # ]: 0 : if (idxd->batch_idx_read == idxd->batch_idx_write)
223 : : return 0;
224 : :
225 : 0 : bstatus = idxd->batch_comp_ring[idxd->batch_idx_read].status;
226 : : /* now check if next batch is complete and successful */
227 [ # # # # ]: 0 : if (bstatus == IDXD_COMP_STATUS_SUCCESS) {
228 : : /* since the batch idx ring stores the start of each batch, pre-increment to lookup
229 : : * start of next batch.
230 : : */
231 [ # # # # ]: 0 : if (++idxd->batch_idx_read > idxd->max_batches)
232 : 0 : idxd->batch_idx_read = 0;
233 : 0 : idxd->ids_avail = idxd->batch_idx_ring[idxd->batch_idx_read];
234 : :
235 : 0 : ret = RTE_MIN((uint16_t)(idxd->ids_avail - idxd->ids_returned), max_ops);
236 : 0 : idxd->ids_returned += ret;
237 [ # # ]: 0 : if (status)
238 : 0 : memset(status, RTE_DMA_STATUS_SUCCESSFUL, ret * sizeof(*status));
239 : 0 : return ret;
240 : : }
241 : : /* check if batch is incomplete */
242 [ # # # # ]: 0 : else if (bstatus == IDXD_COMP_STATUS_INCOMPLETE)
243 : : return 0;
244 : :
245 : : return -1; /* error case */
246 : : }
247 : :
248 : : __use_avx2
249 : : static inline uint16_t
250 [ # # ]: 0 : batch_completed(struct idxd_dmadev *idxd, uint16_t max_ops, bool *has_error)
251 : : {
252 : : uint16_t i;
253 : : uint16_t b_start, b_end, next_batch;
254 : :
255 : : int ret = batch_ok(idxd, max_ops, NULL);
256 : : if (ret >= 0)
257 : 0 : return ret;
258 : :
259 : : /* ERROR case, not successful, not incomplete */
260 : : /* Get the batch size, and special case size 1.
261 : : * once we identify the actual failure job, return other jobs, then update
262 : : * the batch ring indexes to make it look like the first job of the batch has failed.
263 : : * Subsequent calls here will always return zero packets, and the error must be cleared by
264 : : * calling the completed_status() function.
265 : : */
266 : 0 : next_batch = (idxd->batch_idx_read + 1);
267 [ # # ]: 0 : if (next_batch > idxd->max_batches)
268 : : next_batch = 0;
269 : 0 : b_start = idxd->batch_idx_ring[idxd->batch_idx_read];
270 : 0 : b_end = idxd->batch_idx_ring[next_batch];
271 : :
272 [ # # ]: 0 : if (b_end - b_start == 1) { /* not a batch */
273 : 0 : *has_error = true;
274 : 0 : return 0;
275 : : }
276 : :
277 [ # # ]: 0 : for (i = b_start; i < b_end; i++) {
278 : 0 : struct idxd_completion *c = (void *)&idxd->desc_ring[i & idxd->desc_ring_mask];
279 [ # # ]: 0 : if (c->status > IDXD_COMP_STATUS_SUCCESS) /* ignore incomplete(0) and success(1) */
280 : : break;
281 : : }
282 : 0 : ret = RTE_MIN((uint16_t)(i - idxd->ids_returned), max_ops);
283 [ # # ]: 0 : if (ret < max_ops)
284 : 0 : *has_error = true; /* we got up to the point of error */
285 : 0 : idxd->ids_avail = idxd->ids_returned += ret;
286 : :
287 : : /* to ensure we can call twice and just return 0, set start of batch to where we finished */
288 : 0 : idxd->batch_comp_ring[idxd->batch_idx_read].completed_size -= ret;
289 : 0 : idxd->batch_idx_ring[idxd->batch_idx_read] += ret;
290 [ # # ]: 0 : if (idxd->batch_idx_ring[next_batch] - idxd->batch_idx_ring[idxd->batch_idx_read] == 1) {
291 : : /* copy over the descriptor status to the batch ring as if no batch */
292 : 0 : uint16_t d_idx = idxd->batch_idx_ring[idxd->batch_idx_read] & idxd->desc_ring_mask;
293 : 0 : struct idxd_completion *desc_comp = (void *)&idxd->desc_ring[d_idx];
294 : 0 : idxd->batch_comp_ring[idxd->batch_idx_read].status = desc_comp->status;
295 : : }
296 : :
297 : : return ret;
298 : : }
299 : :
300 : : __use_avx2
301 : : static uint16_t
302 : 0 : batch_completed_status(struct idxd_dmadev *idxd, uint16_t max_ops, enum rte_dma_status_code *status)
303 : : {
304 : : uint16_t next_batch;
305 : :
306 [ # # ]: 0 : int ret = batch_ok(idxd, max_ops, status);
307 : : if (ret >= 0)
308 : 0 : return ret;
309 : :
310 : : /* ERROR case, not successful, not incomplete */
311 : : /* Get the batch size, and special case size 1.
312 : : */
313 : 0 : next_batch = (idxd->batch_idx_read + 1);
314 [ # # ]: 0 : if (next_batch > idxd->max_batches)
315 : : next_batch = 0;
316 : 0 : const uint16_t b_start = idxd->batch_idx_ring[idxd->batch_idx_read];
317 : 0 : const uint16_t b_end = idxd->batch_idx_ring[next_batch];
318 : 0 : const uint16_t b_len = b_end - b_start;
319 [ # # ]: 0 : if (b_len == 1) {/* not a batch */
320 [ # # # # : 0 : *status = get_comp_status(&idxd->batch_comp_ring[idxd->batch_idx_read]);
# # ]
321 : : if (status != RTE_DMA_STATUS_SUCCESSFUL)
322 : 0 : idxd->stats.errors++;
323 : 0 : idxd->ids_avail++;
324 : 0 : idxd->ids_returned++;
325 : 0 : idxd->batch_idx_read = next_batch;
326 : 0 : return 1;
327 : : }
328 : :
329 : : /* not a single-element batch, need to process more.
330 : : * Scenarios:
331 : : * 1. max_ops >= batch_size - can fit everything, simple case
332 : : * - loop through completed ops and then add on any not-attempted ones
333 : : * 2. max_ops < batch_size - can't fit everything, more complex case
334 : : * - loop through completed/incomplete and stop when hit max_ops
335 : : * - adjust the batch descriptor to update where we stopped, with appropriate bcount
336 : : * - if bcount is to be exactly 1, update the batch descriptor as it will be treated as
337 : : * non-batch next time.
338 : : */
339 : 0 : const uint16_t bcount = idxd->batch_comp_ring[idxd->batch_idx_read].completed_size;
340 [ # # # # ]: 0 : for (ret = 0; ret < b_len && ret < max_ops; ret++) {
341 : 0 : struct idxd_completion *c = (void *)
342 : 0 : &idxd->desc_ring[(b_start + ret) & idxd->desc_ring_mask];
343 [ # # ]: 0 : status[ret] = (ret < bcount) ? get_comp_status(c) : RTE_DMA_STATUS_NOT_ATTEMPTED;
344 [ # # ]: 0 : if (status[ret] != RTE_DMA_STATUS_SUCCESSFUL)
345 : 0 : idxd->stats.errors++;
346 : : }
347 : 0 : idxd->ids_avail = idxd->ids_returned += ret;
348 : :
349 : : /* everything fit */
350 [ # # ]: 0 : if (ret == b_len) {
351 : 0 : idxd->batch_idx_read = next_batch;
352 : 0 : return ret;
353 : : }
354 : :
355 : : /* set up for next time, update existing batch descriptor & start idx at batch_idx_read */
356 : 0 : idxd->batch_idx_ring[idxd->batch_idx_read] += ret;
357 [ # # ]: 0 : if (ret > bcount) {
358 : : /* we have only incomplete ones - set batch completed size to 0 */
359 : 0 : struct idxd_completion *comp = &idxd->batch_comp_ring[idxd->batch_idx_read];
360 : 0 : comp->completed_size = 0;
361 : : /* if there is only one descriptor left, job skipped so set flag appropriately */
362 [ # # ]: 0 : if (b_len - ret == 1)
363 : 0 : comp->status = IDXD_COMP_STATUS_SKIPPED;
364 : : } else {
365 : 0 : struct idxd_completion *comp = &idxd->batch_comp_ring[idxd->batch_idx_read];
366 : 0 : comp->completed_size -= ret;
367 : : /* if there is only one descriptor left, copy status info straight to desc */
368 [ # # ]: 0 : if (comp->completed_size == 1) {
369 : 0 : struct idxd_completion *c = (void *)
370 : 0 : &idxd->desc_ring[(b_start + ret) & idxd->desc_ring_mask];
371 : 0 : comp->status = c->status;
372 : : /* individual descs can be ok without writeback, but not batches */
373 [ # # ]: 0 : if (comp->status == IDXD_COMP_STATUS_INCOMPLETE)
374 : 0 : comp->status = IDXD_COMP_STATUS_SUCCESS;
375 [ # # ]: 0 : } else if (bcount == b_len) {
376 : : /* check if we still have an error, and clear flag if not */
377 : : uint16_t i;
378 [ # # ]: 0 : for (i = b_start + ret; i < b_end; i++) {
379 : 0 : struct idxd_completion *c = (void *)
380 : 0 : &idxd->desc_ring[i & idxd->desc_ring_mask];
381 [ # # ]: 0 : if (c->status > IDXD_COMP_STATUS_SUCCESS)
382 : : break;
383 : : }
384 [ # # ]: 0 : if (i == b_end) /* no errors */
385 : 0 : comp->status = IDXD_COMP_STATUS_SUCCESS;
386 : : }
387 : : }
388 : :
389 : : return ret;
390 : : }
391 : :
392 : : __use_avx2
393 : : uint16_t
394 : 0 : idxd_completed(void *dev_private, uint16_t qid __rte_unused, uint16_t max_ops,
395 : : uint16_t *last_idx, bool *has_error)
396 : : {
397 : : struct idxd_dmadev *idxd = dev_private;
398 : : uint16_t batch, ret = 0;
399 : :
400 : : do {
401 : 0 : batch = batch_completed(idxd, max_ops - ret, has_error);
402 : 0 : ret += batch;
403 [ # # # # ]: 0 : } while (batch > 0 && *has_error == false);
404 : :
405 : 0 : idxd->stats.completed += ret;
406 : 0 : *last_idx = idxd->ids_returned - 1;
407 : 0 : return ret;
408 : : }
409 : :
410 : : __use_avx2
411 : : uint16_t
412 : 0 : idxd_completed_status(void *dev_private, uint16_t qid __rte_unused, uint16_t max_ops,
413 : : uint16_t *last_idx, enum rte_dma_status_code *status)
414 : : {
415 : : struct idxd_dmadev *idxd = dev_private;
416 : : uint16_t batch, ret = 0;
417 : :
418 : : do {
419 : 0 : batch = batch_completed_status(idxd, max_ops - ret, &status[ret]);
420 : 0 : ret += batch;
421 [ # # ]: 0 : } while (batch > 0);
422 : :
423 : 0 : idxd->stats.completed += ret;
424 : 0 : *last_idx = idxd->ids_returned - 1;
425 : 0 : return ret;
426 : : }
427 : :
428 : : int
429 : 0 : idxd_dump(const struct rte_dma_dev *dev, FILE *f)
430 : : {
431 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
432 : : unsigned int i;
433 : :
434 : : fprintf(f, "== IDXD Private Data ==\n");
435 : 0 : fprintf(f, " Portal: %p\n", idxd->portal);
436 : 0 : fprintf(f, " Config: { ring_size: %u }\n",
437 : 0 : idxd->qcfg.nb_desc);
438 : 0 : fprintf(f, " Batch ring (sz = %u, max_batches = %u):\n\t",
439 : 0 : idxd->max_batches + 1, idxd->max_batches);
440 [ # # ]: 0 : for (i = 0; i <= idxd->max_batches; i++) {
441 : 0 : fprintf(f, " %u ", idxd->batch_idx_ring[i]);
442 [ # # # # ]: 0 : if (i == idxd->batch_idx_read && i == idxd->batch_idx_write)
443 : : fprintf(f, "[rd ptr, wr ptr] ");
444 [ # # ]: 0 : else if (i == idxd->batch_idx_read)
445 : : fprintf(f, "[rd ptr] ");
446 [ # # ]: 0 : else if (i == idxd->batch_idx_write)
447 : : fprintf(f, "[wr ptr] ");
448 [ # # ]: 0 : if (i == idxd->max_batches)
449 : : fprintf(f, "\n");
450 : : }
451 : :
452 : 0 : fprintf(f, " Curr batch: start = %u, size = %u\n", idxd->batch_start, idxd->batch_size);
453 : 0 : fprintf(f, " IDS: avail = %u, returned: %u\n", idxd->ids_avail, idxd->ids_returned);
454 : 0 : return 0;
455 : : }
456 : :
457 : : int
458 : 0 : idxd_stats_get(const struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
459 : : struct rte_dma_stats *stats, uint32_t stats_sz)
460 : : {
461 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
462 [ # # ]: 0 : if (stats_sz < sizeof(*stats))
463 : : return -EINVAL;
464 : 0 : *stats = idxd->stats;
465 : 0 : return 0;
466 : : }
467 : :
468 : : int
469 : 0 : idxd_stats_reset(struct rte_dma_dev *dev, uint16_t vchan __rte_unused)
470 : : {
471 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
472 : 0 : idxd->stats = (struct rte_dma_stats){0};
473 : 0 : return 0;
474 : : }
475 : :
476 : : int
477 : 0 : idxd_info_get(const struct rte_dma_dev *dev, struct rte_dma_info *info, uint32_t size)
478 : : {
479 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
480 : :
481 [ # # ]: 0 : if (size < sizeof(*info))
482 : : return -EINVAL;
483 : :
484 : 0 : *info = (struct rte_dma_info) {
485 : : .dev_capa = RTE_DMA_CAPA_MEM_TO_MEM | RTE_DMA_CAPA_HANDLES_ERRORS |
486 : : RTE_DMA_CAPA_OPS_COPY | RTE_DMA_CAPA_OPS_FILL,
487 : : .max_vchans = 1,
488 : : .max_desc = 4096,
489 : : .min_desc = 64,
490 : : };
491 [ # # ]: 0 : if (idxd->sva_support)
492 : 0 : info->dev_capa |= RTE_DMA_CAPA_SVA;
493 : : return 0;
494 : : }
495 : :
496 : : uint16_t
497 : 0 : idxd_burst_capacity(const void *dev_private, uint16_t vchan __rte_unused)
498 : : {
499 : : const struct idxd_dmadev *idxd = dev_private;
500 : 0 : uint16_t write_idx = idxd->batch_start + idxd->batch_size;
501 : : uint16_t used_space;
502 : :
503 : : /* Check for space in the batch ring */
504 [ # # # # ]: 0 : if ((idxd->batch_idx_read == 0 && idxd->batch_idx_write == idxd->max_batches) ||
505 [ # # ]: 0 : idxd->batch_idx_write + 1 == idxd->batch_idx_read)
506 : : return 0;
507 : :
508 : : /* Subtract and mask to get in correct range */
509 : 0 : used_space = (write_idx - idxd->ids_returned) & idxd->desc_ring_mask;
510 : :
511 : 0 : const int ret = RTE_MIN((idxd->desc_ring_mask - used_space),
512 : : (idxd->max_batch_size - idxd->batch_size));
513 [ # # ]: 0 : return ret < 0 ? 0 : (uint16_t)ret;
514 : : }
515 : :
516 : : int
517 : 0 : idxd_configure(struct rte_dma_dev *dev __rte_unused, const struct rte_dma_conf *dev_conf,
518 : : uint32_t conf_sz)
519 : : {
520 [ # # ]: 0 : if (sizeof(struct rte_dma_conf) != conf_sz)
521 : : return -EINVAL;
522 : :
523 [ # # ]: 0 : if (dev_conf->nb_vchans != 1)
524 : 0 : return -EINVAL;
525 : : return 0;
526 : : }
527 : :
528 : : int
529 : 0 : idxd_vchan_setup(struct rte_dma_dev *dev, uint16_t vchan __rte_unused,
530 : : const struct rte_dma_vchan_conf *qconf, uint32_t qconf_sz)
531 : : {
532 : 0 : struct idxd_dmadev *idxd = dev->fp_obj->dev_private;
533 : 0 : uint16_t max_desc = qconf->nb_desc;
534 : :
535 [ # # ]: 0 : if (sizeof(struct rte_dma_vchan_conf) != qconf_sz)
536 : : return -EINVAL;
537 : :
538 : 0 : idxd->qcfg = *qconf;
539 : :
540 [ # # ]: 0 : if (!rte_is_power_of_2(max_desc))
541 : 0 : max_desc = rte_align32pow2(max_desc);
542 : 0 : IDXD_PMD_DEBUG("DMA dev %u using %u descriptors", dev->data->dev_id, max_desc);
543 : 0 : idxd->desc_ring_mask = max_desc - 1;
544 : 0 : idxd->qcfg.nb_desc = max_desc;
545 : :
546 : : /* in case we are reconfiguring a device, free any existing memory */
547 : 0 : rte_free(idxd->desc_ring);
548 : :
549 : : /* allocate the descriptor ring at 2x size as batches can't wrap */
550 : 0 : idxd->desc_ring = rte_zmalloc(NULL, sizeof(*idxd->desc_ring) * max_desc * 2, 0);
551 [ # # ]: 0 : if (idxd->desc_ring == NULL)
552 : : return -ENOMEM;
553 : 0 : idxd->desc_iova = rte_mem_virt2iova(idxd->desc_ring);
554 : :
555 : 0 : idxd->batch_idx_read = 0;
556 : 0 : idxd->batch_idx_write = 0;
557 : 0 : idxd->batch_start = 0;
558 : 0 : idxd->batch_size = 0;
559 : 0 : idxd->ids_returned = 0;
560 : 0 : idxd->ids_avail = 0;
561 : :
562 : 0 : memset(idxd->batch_comp_ring, 0, sizeof(*idxd->batch_comp_ring) *
563 : 0 : (idxd->max_batches + 1));
564 : 0 : return 0;
565 : : }
566 : :
567 : : int
568 : 0 : idxd_dmadev_create(const char *name, struct rte_device *dev,
569 : : const struct idxd_dmadev *base_idxd,
570 : : const struct rte_dma_dev_ops *ops)
571 : : {
572 : : struct idxd_dmadev *idxd = NULL;
573 : : struct rte_dma_dev *dmadev = NULL;
574 : : int ret = 0;
575 : :
576 : : RTE_BUILD_BUG_ON(sizeof(struct idxd_hw_desc) != 64);
577 : : RTE_BUILD_BUG_ON(offsetof(struct idxd_hw_desc, size) != 32);
578 : : RTE_BUILD_BUG_ON(sizeof(struct idxd_completion) != 32);
579 : :
580 [ # # ]: 0 : if (!name) {
581 : 0 : IDXD_PMD_ERR("Invalid name of the device!");
582 : : ret = -EINVAL;
583 : 0 : goto cleanup;
584 : : }
585 : :
586 : : /* Allocate device structure */
587 : 0 : dmadev = rte_dma_pmd_allocate(name, dev->numa_node, sizeof(struct idxd_dmadev));
588 [ # # ]: 0 : if (dmadev == NULL) {
589 : 0 : IDXD_PMD_ERR("Unable to allocate dma device");
590 : : ret = -ENOMEM;
591 : 0 : goto cleanup;
592 : : }
593 : 0 : dmadev->dev_ops = ops;
594 : 0 : dmadev->device = dev;
595 : :
596 : 0 : dmadev->fp_obj->copy = idxd_enqueue_copy;
597 : 0 : dmadev->fp_obj->fill = idxd_enqueue_fill;
598 : 0 : dmadev->fp_obj->submit = idxd_submit;
599 : 0 : dmadev->fp_obj->completed = idxd_completed;
600 : 0 : dmadev->fp_obj->completed_status = idxd_completed_status;
601 : 0 : dmadev->fp_obj->burst_capacity = idxd_burst_capacity;
602 : 0 : dmadev->fp_obj->dev_private = dmadev->data->dev_private;
603 : :
604 [ # # ]: 0 : if (rte_eal_process_type() != RTE_PROC_PRIMARY)
605 : : return 0;
606 : :
607 : 0 : idxd = dmadev->data->dev_private;
608 : 0 : *idxd = *base_idxd; /* copy over the main fields already passed in */
609 : 0 : idxd->dmadev = dmadev;
610 : :
611 : : /* allocate batch index ring and completion ring.
612 : : * The +1 is because we can never fully use
613 : : * the ring, otherwise read == write means both full and empty.
614 : : */
615 : 0 : idxd->batch_comp_ring = rte_zmalloc_socket(NULL, (sizeof(idxd->batch_idx_ring[0]) +
616 : 0 : sizeof(idxd->batch_comp_ring[0])) * (idxd->max_batches + 1),
617 : : sizeof(idxd->batch_comp_ring[0]), dev->numa_node);
618 [ # # ]: 0 : if (idxd->batch_comp_ring == NULL) {
619 : 0 : IDXD_PMD_ERR("Unable to reserve memory for batch data");
620 : : ret = -ENOMEM;
621 : 0 : goto cleanup;
622 : : }
623 : 0 : idxd->batch_idx_ring = (void *)&idxd->batch_comp_ring[idxd->max_batches+1];
624 : 0 : idxd->batch_iova = rte_mem_virt2iova(idxd->batch_comp_ring);
625 : :
626 : 0 : idxd->dmadev->state = RTE_DMA_DEV_READY;
627 : :
628 : 0 : return 0;
629 : :
630 : 0 : cleanup:
631 [ # # ]: 0 : if (dmadev)
632 : 0 : rte_dma_pmd_release(name);
633 : :
634 : : return ret;
635 : : }
636 : :
637 : : int idxd_pmd_logtype;
638 : :
639 [ - + ]: 251 : RTE_LOG_REGISTER_DEFAULT(idxd_pmd_logtype, WARNING);
|