Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2021 HiSilicon Limited
3 : : * Copyright(c) 2021 Intel Corporation
4 : : */
5 : :
6 : : #include <inttypes.h>
7 : :
8 : : #include <rte_dmadev.h>
9 : : #include <rte_mbuf.h>
10 : : #include <rte_pause.h>
11 : : #include <rte_cycles.h>
12 : : #include <rte_random.h>
13 : : #include <rte_bus_vdev.h>
14 : : #include <rte_dmadev_pmd.h>
15 : :
16 : : #include "test.h"
17 : : #include "test_dmadev_api.h"
18 : :
19 : : #define ERR_RETURN(...) do { print_err(__func__, __LINE__, __VA_ARGS__); return -1; } while (0)
20 : :
21 : : #define TEST_NAME_MAX_LEN 80
22 : : #define TEST_RINGSIZE 512
23 : : #define COPY_LEN 2048
24 : :
25 : : static struct rte_dma_info info;
26 : : static struct rte_mempool *pool;
27 : : static bool check_err_stats;
28 : : static int16_t test_dev_id;
29 : : static uint16_t id_count;
30 : : static uint16_t vchan;
31 : :
32 : : enum {
33 : : TEST_PARAM_REMOTE_ADDR = 0,
34 : : TEST_PARAM_MAX,
35 : : };
36 : :
37 : : static const char * const dma_test_param[] = {
38 : : [TEST_PARAM_REMOTE_ADDR] = "remote_addr",
39 : : };
40 : :
41 : : static uint64_t env_test_param[TEST_PARAM_MAX];
42 : :
43 : : enum {
44 : : TEST_M2D_AUTO_FREE = 0,
45 : : TEST_MAX,
46 : : };
47 : :
48 : : struct dma_add_test {
49 : : const char *name;
50 : : bool enabled;
51 : : };
52 : :
53 : : struct dma_add_test dma_add_test[] = {
54 : : [TEST_M2D_AUTO_FREE] = {.name = "m2d_auto_free", .enabled = false},
55 : : };
56 : :
57 : : static void
58 : : __rte_format_printf(3, 4)
59 : 0 : print_err(const char *func, int lineno, const char *format, ...)
60 : : {
61 : : va_list ap;
62 : :
63 : 0 : fprintf(stderr, "In %s:%d - ", func, lineno);
64 : 0 : va_start(ap, format);
65 : 0 : vfprintf(stderr, format, ap);
66 : 0 : va_end(ap);
67 : 0 : }
68 : :
69 : : struct runtest_param {
70 : : const char name[TEST_NAME_MAX_LEN];
71 : : int (*test_fn)(int16_t dev_id, uint16_t vchan);
72 : : int iterations;
73 : : };
74 : :
75 : : static int
76 : 0 : runtest(const void *args)
77 : : {
78 : : int (*test_fn)(int16_t dev_id, uint16_t vchan);
79 : : const struct runtest_param *param = args;
80 : : struct rte_dma_stats stats;
81 : : const char *printable;
82 : : int iterations;
83 : : int16_t dev_id;
84 : : int i;
85 : :
86 : 0 : printable = param->name;
87 : 0 : iterations = param->iterations;
88 : 0 : test_fn = param->test_fn;
89 : 0 : dev_id = test_dev_id;
90 : :
91 : 0 : rte_dma_stats_reset(dev_id, vchan);
92 : 0 : printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
93 [ # # ]: 0 : check_err_stats ? " " : "(errors expected)");
94 [ # # ]: 0 : for (i = 0; i < iterations; i++) {
95 [ # # ]: 0 : if (test_fn(dev_id, vchan) != 0)
96 : : return -1;
97 : :
98 : 0 : rte_dma_stats_get(dev_id, 0, &stats);
99 : 0 : printf("Ops submitted: %"PRIu64"\t", stats.submitted);
100 : 0 : printf("Ops completed: %"PRIu64"\t", stats.completed);
101 : 0 : printf("Errors: %"PRIu64"\r", stats.errors);
102 : :
103 [ # # ]: 0 : if (stats.completed != stats.submitted)
104 : 0 : ERR_RETURN("\nError, not all submitted jobs are reported as completed\n");
105 [ # # # # ]: 0 : if (check_err_stats && stats.errors != 0)
106 : 0 : ERR_RETURN("\nErrors reported during op processing, aborting tests\n");
107 : : }
108 : : printf("\n");
109 : 0 : return 0;
110 : : }
111 : :
112 : : static void
113 : 0 : await_hw(int16_t dev_id, uint16_t vchan)
114 : : {
115 : : enum rte_dma_vchan_status st;
116 : :
117 [ # # ]: 0 : if (rte_dma_vchan_status(dev_id, vchan, &st) < 0) {
118 : : /* for drivers that don't support this op, just sleep for 1 millisecond */
119 : 0 : rte_delay_us_sleep(1000);
120 : 0 : return;
121 : : }
122 : :
123 : : /* for those that do, *max* end time is one second from now, but all should be faster */
124 : 0 : const uint64_t end_cycles = rte_get_timer_cycles() + rte_get_timer_hz();
125 [ # # # # ]: 0 : while (st == RTE_DMA_VCHAN_ACTIVE && rte_get_timer_cycles() < end_cycles) {
126 : : rte_pause();
127 : 0 : rte_dma_vchan_status(dev_id, vchan, &st);
128 : : }
129 : : }
130 : :
131 : : /* run a series of copy tests just using some different options for enqueues and completions */
132 : : static int
133 : 0 : do_multi_copies(int16_t dev_id, uint16_t vchan,
134 : : int split_batches, /* submit 2 x 16 or 1 x 32 burst */
135 : : int split_completions, /* gather 2 x 16 or 1 x 32 completions */
136 : : int use_completed_status) /* use completed or completed_status function */
137 : : {
138 : : struct rte_mbuf *srcs[32], *dsts[32];
139 : : enum rte_dma_status_code sc[32];
140 : : unsigned int i, j;
141 : 0 : bool dma_err = false;
142 : :
143 : : /* Enqueue burst of copies and hit doorbell */
144 [ # # ]: 0 : for (i = 0; i < RTE_DIM(srcs); i++) {
145 : : uint64_t *src_data;
146 : :
147 [ # # ]: 0 : if (split_batches && i == RTE_DIM(srcs) / 2)
148 : 0 : rte_dma_submit(dev_id, vchan);
149 : :
150 : 0 : srcs[i] = rte_pktmbuf_alloc(pool);
151 : 0 : dsts[i] = rte_pktmbuf_alloc(pool);
152 [ # # # # ]: 0 : if (srcs[i] == NULL || dsts[i] == NULL)
153 : 0 : ERR_RETURN("Error allocating buffers\n");
154 : :
155 : 0 : src_data = rte_pktmbuf_mtod(srcs[i], uint64_t *);
156 [ # # ]: 0 : for (j = 0; j < COPY_LEN/sizeof(uint64_t); j++)
157 : 0 : src_data[j] = rte_rand();
158 : :
159 : 0 : if (rte_dma_copy(dev_id, vchan, rte_mbuf_data_iova(srcs[i]),
160 [ # # ]: 0 : rte_mbuf_data_iova(dsts[i]), COPY_LEN, 0) != id_count++)
161 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", i);
162 : : }
163 : 0 : rte_dma_submit(dev_id, vchan);
164 : :
165 : 0 : await_hw(dev_id, vchan);
166 : :
167 [ # # ]: 0 : if (split_completions) {
168 : : /* gather completions in two halves */
169 : : uint16_t half_len = RTE_DIM(srcs) / 2;
170 : 0 : int ret = rte_dma_completed(dev_id, vchan, half_len, NULL, &dma_err);
171 [ # # # # ]: 0 : if (ret != half_len || dma_err)
172 : 0 : ERR_RETURN("Error with rte_dma_completed - first half. ret = %d, expected ret = %u, dma_err = %d\n",
173 : : ret, half_len, dma_err);
174 : :
175 : 0 : ret = rte_dma_completed(dev_id, vchan, half_len, NULL, &dma_err);
176 [ # # # # ]: 0 : if (ret != half_len || dma_err)
177 : 0 : ERR_RETURN("Error with rte_dma_completed - second half. ret = %d, expected ret = %u, dma_err = %d\n",
178 : : ret, half_len, dma_err);
179 : : } else {
180 : : /* gather all completions in one go, using either
181 : : * completed or completed_status fns
182 : : */
183 [ # # ]: 0 : if (!use_completed_status) {
184 : 0 : int n = rte_dma_completed(dev_id, vchan, RTE_DIM(srcs), NULL, &dma_err);
185 [ # # # # ]: 0 : if (n != RTE_DIM(srcs) || dma_err)
186 : 0 : ERR_RETURN("Error with rte_dma_completed, %u [expected: %zu], dma_err = %d\n",
187 : : n, RTE_DIM(srcs), dma_err);
188 : : } else {
189 : 0 : int n = rte_dma_completed_status(dev_id, vchan, RTE_DIM(srcs), NULL, sc);
190 [ # # ]: 0 : if (n != RTE_DIM(srcs))
191 : 0 : ERR_RETURN("Error with rte_dma_completed_status, %u [expected: %zu]\n",
192 : : n, RTE_DIM(srcs));
193 : :
194 [ # # ]: 0 : for (j = 0; j < (uint16_t)n; j++)
195 [ # # ]: 0 : if (sc[j] != RTE_DMA_STATUS_SUCCESSFUL)
196 : 0 : ERR_RETURN("Error with rte_dma_completed_status, job %u reports failure [code %u]\n",
197 : : j, sc[j]);
198 : : }
199 : : }
200 : :
201 : : /* check for empty */
202 : : int ret = use_completed_status ?
203 [ # # ]: 0 : rte_dma_completed_status(dev_id, vchan, RTE_DIM(srcs), NULL, sc) :
204 : : rte_dma_completed(dev_id, vchan, RTE_DIM(srcs), NULL, &dma_err);
205 [ # # ]: 0 : if (ret != 0)
206 : 0 : ERR_RETURN("Error with completion check - ops unexpectedly returned\n");
207 : :
208 [ # # ]: 0 : for (i = 0; i < RTE_DIM(srcs); i++) {
209 : : char *src_data, *dst_data;
210 : :
211 : 0 : src_data = rte_pktmbuf_mtod(srcs[i], char *);
212 : 0 : dst_data = rte_pktmbuf_mtod(dsts[i], char *);
213 [ # # ]: 0 : for (j = 0; j < COPY_LEN; j++)
214 [ # # ]: 0 : if (src_data[j] != dst_data[j])
215 : 0 : ERR_RETURN("Error with copy of packet %u, byte %u\n", i, j);
216 : :
217 : 0 : rte_pktmbuf_free(srcs[i]);
218 : 0 : rte_pktmbuf_free(dsts[i]);
219 : : }
220 : : return 0;
221 : : }
222 : :
223 : : static int
224 : 0 : test_single_copy(int16_t dev_id, uint16_t vchan)
225 : : {
226 : : uint16_t i;
227 : : uint16_t id;
228 : : enum rte_dma_status_code status;
229 : : struct rte_mbuf *src, *dst;
230 : : char *src_data, *dst_data;
231 : :
232 : 0 : src = rte_pktmbuf_alloc(pool);
233 : 0 : dst = rte_pktmbuf_alloc(pool);
234 : 0 : src_data = rte_pktmbuf_mtod(src, char *);
235 : 0 : dst_data = rte_pktmbuf_mtod(dst, char *);
236 : :
237 [ # # ]: 0 : for (i = 0; i < COPY_LEN; i++)
238 : 0 : src_data[i] = rte_rand() & 0xFF;
239 : :
240 : 0 : id = rte_dma_copy(dev_id, vchan, rte_pktmbuf_iova(src), rte_pktmbuf_iova(dst),
241 : : COPY_LEN, RTE_DMA_OP_FLAG_SUBMIT);
242 [ # # ]: 0 : if (id != id_count)
243 : 0 : ERR_RETURN("Error with rte_dma_copy, got %u, expected %u\n",
244 : : id, id_count);
245 : :
246 : : /* give time for copy to finish, then check it was done */
247 : 0 : await_hw(dev_id, vchan);
248 : :
249 [ # # ]: 0 : for (i = 0; i < COPY_LEN; i++)
250 [ # # ]: 0 : if (dst_data[i] != src_data[i])
251 : 0 : ERR_RETURN("Data mismatch at char %u [Got %02x not %02x]\n", i,
252 : : dst_data[i], src_data[i]);
253 : :
254 : : /* now check completion works */
255 : 0 : id = ~id;
256 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
257 : 0 : ERR_RETURN("Error with rte_dma_completed\n");
258 : :
259 [ # # ]: 0 : if (id != id_count)
260 : 0 : ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
261 : : id, id_count);
262 : :
263 : : /* check for completed and id when no job done */
264 : 0 : id = ~id;
265 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
266 : 0 : ERR_RETURN("Error with rte_dma_completed when no job done\n");
267 [ # # ]: 0 : if (id != id_count)
268 : 0 : ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
269 : : id, id_count);
270 : :
271 : : /* check for completed_status and id when no job done */
272 : 0 : id = ~id;
273 [ # # ]: 0 : if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
274 : 0 : ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
275 [ # # ]: 0 : if (id != id_count)
276 : 0 : ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
277 : : id, id_count);
278 : :
279 : 0 : rte_pktmbuf_free(src);
280 : 0 : rte_pktmbuf_free(dst);
281 : :
282 : : /* now check completion returns nothing more */
283 [ # # ]: 0 : if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
284 : 0 : ERR_RETURN("Error with rte_dma_completed in empty check\n");
285 : :
286 : 0 : id_count++;
287 : :
288 : 0 : return 0;
289 : : }
290 : :
291 : : static int
292 : 0 : test_enqueue_copies(int16_t dev_id, uint16_t vchan)
293 : : {
294 : : unsigned int i;
295 : :
296 : : /* test doing a single copy */
297 [ # # ]: 0 : if (test_single_copy(dev_id, vchan) < 0)
298 : : return -1;
299 : :
300 : : /* test doing a multiple single copies */
301 : : do {
302 : : uint16_t id;
303 : : const uint16_t max_ops = 4;
304 : : struct rte_mbuf *src, *dst;
305 : : char *src_data, *dst_data;
306 : : uint16_t count;
307 : :
308 : 0 : src = rte_pktmbuf_alloc(pool);
309 : 0 : dst = rte_pktmbuf_alloc(pool);
310 : 0 : src_data = rte_pktmbuf_mtod(src, char *);
311 : 0 : dst_data = rte_pktmbuf_mtod(dst, char *);
312 : :
313 [ # # ]: 0 : for (i = 0; i < COPY_LEN; i++)
314 : 0 : src_data[i] = rte_rand() & 0xFF;
315 : :
316 : : /* perform the same copy <max_ops> times */
317 [ # # ]: 0 : for (i = 0; i < max_ops; i++)
318 : 0 : if (rte_dma_copy(dev_id, vchan,
319 : 0 : rte_pktmbuf_iova(src),
320 : 0 : rte_pktmbuf_iova(dst),
321 [ # # ]: 0 : COPY_LEN, RTE_DMA_OP_FLAG_SUBMIT) != id_count++)
322 : 0 : ERR_RETURN("Error with rte_dma_copy\n");
323 : :
324 : 0 : await_hw(dev_id, vchan);
325 : :
326 : : count = rte_dma_completed(dev_id, vchan, max_ops * 2, &id, NULL);
327 [ # # ]: 0 : if (count != max_ops)
328 : 0 : ERR_RETURN("Error with rte_dma_completed, got %u not %u\n",
329 : : count, max_ops);
330 : :
331 [ # # ]: 0 : if (id != id_count - 1)
332 : 0 : ERR_RETURN("Error, incorrect job id returned: got %u not %u\n",
333 : : id, id_count - 1);
334 : :
335 [ # # ]: 0 : for (i = 0; i < COPY_LEN; i++)
336 [ # # ]: 0 : if (dst_data[i] != src_data[i])
337 : 0 : ERR_RETURN("Data mismatch at char %u\n", i);
338 : :
339 : 0 : rte_pktmbuf_free(src);
340 : 0 : rte_pktmbuf_free(dst);
341 : : } while (0);
342 : :
343 : : /* test doing multiple copies */
344 : 0 : return do_multi_copies(dev_id, vchan, 0, 0, 0) /* enqueue and complete 1 batch at a time */
345 : : /* enqueue 2 batches and then complete both */
346 [ # # ]: 0 : || do_multi_copies(dev_id, vchan, 1, 0, 0)
347 : : /* enqueue 1 batch, then complete in two halves */
348 [ # # ]: 0 : || do_multi_copies(dev_id, vchan, 0, 1, 0)
349 : : /* test using completed_status in place of regular completed API */
350 [ # # # # ]: 0 : || do_multi_copies(dev_id, vchan, 0, 0, 1);
351 : : }
352 : :
353 : : static int
354 : 0 : test_stop_start(int16_t dev_id, uint16_t vchan)
355 : : {
356 : : /* device is already started on input, should be (re)started on output */
357 : :
358 : 0 : uint16_t id = 0;
359 : 0 : enum rte_dma_status_code status = RTE_DMA_STATUS_SUCCESSFUL;
360 : :
361 : : /* - test stopping a device works ok,
362 : : * - then do a start-stop without doing a copy
363 : : * - finally restart the device
364 : : * checking for errors at each stage, and validating we can still copy at the end.
365 : : */
366 [ # # ]: 0 : if (rte_dma_stop(dev_id) < 0)
367 : 0 : ERR_RETURN("Error stopping device\n");
368 : :
369 [ # # ]: 0 : if (rte_dma_start(dev_id) < 0)
370 : 0 : ERR_RETURN("Error restarting device\n");
371 [ # # ]: 0 : if (rte_dma_stop(dev_id) < 0)
372 : 0 : ERR_RETURN("Error stopping device after restart (no jobs executed)\n");
373 : :
374 [ # # ]: 0 : if (rte_dma_start(dev_id) < 0)
375 : 0 : ERR_RETURN("Error restarting device after multiple stop-starts\n");
376 : :
377 : : /* before doing a copy, we need to know what the next id will be it should
378 : : * either be:
379 : : * - the last completed job before start if driver does not reset id on stop
380 : : * - or -1 i.e. next job is 0, if driver does reset the job ids on stop
381 : : */
382 [ # # ]: 0 : if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
383 : 0 : ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
384 : 0 : id += 1; /* id_count is next job id */
385 [ # # # # ]: 0 : if (id != id_count && id != 0)
386 : 0 : ERR_RETURN("Unexpected next id from device after stop-start. Got %u, expected %u or 0\n",
387 : : id, id_count);
388 : :
389 : 0 : id_count = id;
390 [ # # ]: 0 : if (test_single_copy(dev_id, vchan) < 0)
391 : 0 : ERR_RETURN("Error performing copy after device restart\n");
392 : : return 0;
393 : : }
394 : :
395 : : static int
396 : 0 : test_enqueue_sg_copies(int16_t dev_id, uint16_t vchan)
397 : : {
398 : : unsigned int src_len, dst_len, n_sge, len, i, j, k;
399 : : char orig_src[COPY_LEN], orig_dst[COPY_LEN];
400 : 0 : struct rte_dma_info info = { 0 };
401 : : enum rte_dma_status_code status;
402 : : uint16_t id, n_src, n_dst;
403 : :
404 [ # # ]: 0 : if (rte_dma_info_get(dev_id, &info) < 0)
405 : 0 : ERR_RETURN("Failed to get dev info");
406 : :
407 [ # # ]: 0 : if (info.max_sges < 2)
408 : 0 : ERR_RETURN("Test needs minimum 2 SG pointers");
409 : :
410 : : n_sge = info.max_sges;
411 : :
412 [ # # ]: 0 : for (n_src = 1; n_src <= n_sge; n_src++) {
413 [ # # ]: 0 : for (n_dst = 1; n_dst <= n_sge; n_dst++) {
414 : : /* Normalize SG buffer lengths */
415 : : len = COPY_LEN;
416 : 0 : len -= (len % (n_src * n_dst));
417 : 0 : dst_len = len / n_dst;
418 : 0 : src_len = len / n_src;
419 : :
420 : 0 : struct rte_dma_sge *sg_src = alloca(sizeof(struct rte_dma_sge) * n_sge);
421 : 0 : struct rte_dma_sge *sg_dst = alloca(sizeof(struct rte_dma_sge) * n_sge);
422 : 0 : struct rte_mbuf **src = alloca(sizeof(struct rte_mbuf *) * n_sge);
423 : 0 : struct rte_mbuf **dst = alloca(sizeof(struct rte_mbuf *) * n_sge);
424 : 0 : char **src_data = alloca(sizeof(char *) * n_sge);
425 : 0 : char **dst_data = alloca(sizeof(char *) * n_sge);
426 : :
427 [ # # ]: 0 : for (i = 0 ; i < len; i++)
428 : 0 : orig_src[i] = rte_rand() & 0xFF;
429 : :
430 : 0 : memset(orig_dst, 0, len);
431 : :
432 [ # # ]: 0 : for (i = 0; i < n_src; i++) {
433 : 0 : src[i] = rte_pktmbuf_alloc(pool);
434 : : RTE_ASSERT(src[i] != NULL);
435 : 0 : sg_src[i].addr = rte_pktmbuf_iova(src[i]);
436 : 0 : sg_src[i].length = src_len;
437 : 0 : src_data[i] = rte_pktmbuf_mtod(src[i], char *);
438 : : }
439 : :
440 [ # # ]: 0 : for (k = 0; k < n_dst; k++) {
441 : 0 : dst[k] = rte_pktmbuf_alloc(pool);
442 : : RTE_ASSERT(dst[k] != NULL);
443 : 0 : sg_dst[k].addr = rte_pktmbuf_iova(dst[k]);
444 : 0 : sg_dst[k].length = dst_len;
445 : 0 : dst_data[k] = rte_pktmbuf_mtod(dst[k], char *);
446 : : }
447 : :
448 [ # # ]: 0 : for (i = 0; i < n_src; i++) {
449 [ # # ]: 0 : for (j = 0; j < src_len; j++)
450 : 0 : src_data[i][j] = orig_src[i * src_len + j];
451 : : }
452 : :
453 [ # # ]: 0 : for (k = 0; k < n_dst; k++)
454 : 0 : memset(dst_data[k], 0, dst_len);
455 : :
456 : : printf("\tsrc segs: %2d [seg len: %4d] - dst segs: %2d [seg len : %4d]\n",
457 : : n_src, src_len, n_dst, dst_len);
458 : :
459 : 0 : id = rte_dma_copy_sg(dev_id, vchan, sg_src, sg_dst, n_src, n_dst,
460 : : RTE_DMA_OP_FLAG_SUBMIT);
461 : :
462 [ # # ]: 0 : if (id != id_count)
463 : 0 : ERR_RETURN("Error with rte_dma_copy_sg, got %u, expected %u\n",
464 : : id, id_count);
465 : :
466 : : /* Give time for copy to finish, then check it was done */
467 : 0 : await_hw(dev_id, vchan);
468 : :
469 [ # # ]: 0 : for (k = 0; k < n_dst; k++)
470 : 0 : memcpy((&orig_dst[0] + k * dst_len), dst_data[k], dst_len);
471 : :
472 [ # # ]: 0 : if (memcmp(orig_src, orig_dst, COPY_LEN))
473 : 0 : ERR_RETURN("Data mismatch");
474 : :
475 : : /* Verify completion */
476 : 0 : id = ~id;
477 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
478 : 0 : ERR_RETURN("Error with rte_dma_completed\n");
479 : :
480 : : /* Verify expected index(id_count) */
481 [ # # ]: 0 : if (id != id_count)
482 : 0 : ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
483 : : id, id_count);
484 : :
485 : : /* Check for completed and id when no job done */
486 : 0 : id = ~id;
487 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 0)
488 : 0 : ERR_RETURN("Error with rte_dma_completed when no job done\n");
489 : :
490 [ # # ]: 0 : if (id != id_count)
491 : 0 : ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
492 : : id, id_count);
493 : :
494 : : /* Check for completed_status and id when no job done */
495 : 0 : id = ~id;
496 [ # # ]: 0 : if (rte_dma_completed_status(dev_id, vchan, 1, &id, &status) != 0)
497 : 0 : ERR_RETURN("Error with rte_dma_completed_status when no job done\n");
498 [ # # ]: 0 : if (id != id_count)
499 : 0 : ERR_RETURN("Error:incorrect job id received when no job done, %u [expected %u]\n",
500 : : id, 0);
501 : :
502 [ # # ]: 0 : for (i = 0; i < n_src; i++)
503 : 0 : rte_pktmbuf_free(src[i]);
504 [ # # ]: 0 : for (i = 0; i < n_dst; i++)
505 : 0 : rte_pktmbuf_free(dst[i]);
506 : :
507 : : /* Verify that completion returns nothing more */
508 [ # # ]: 0 : if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
509 : 0 : ERR_RETURN("Error with rte_dma_completed in empty check\n");
510 : :
511 : 0 : id_count++;
512 : : }
513 : : }
514 : : return 0;
515 : : }
516 : :
517 : : static int
518 : 0 : test_single_sva_copy(int16_t dev_id, uint16_t vchan, const char *mem_src,
519 : : char *src, char *dst, uint32_t len)
520 : : {
521 : : uint16_t i, id;
522 : : int ret;
523 : :
524 [ # # ]: 0 : for (i = 0; i < len; i++)
525 : 0 : src[i] = rte_rand() & 0xFF;
526 : :
527 : 0 : ret = rte_dma_copy(dev_id, vchan, (rte_iova_t)src, (rte_iova_t)dst,
528 : : len, RTE_DMA_OP_FLAG_SUBMIT);
529 [ # # ]: 0 : if (ret != id_count)
530 : 0 : ERR_RETURN("Error with %s rte_dma_copy, got %d expected %u\n",
531 : : mem_src, ret, id_count);
532 : :
533 : 0 : await_hw(dev_id, vchan);
534 : :
535 : 0 : id = ~id_count;
536 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
537 : 0 : ERR_RETURN("Error with %s rte_dma_completed\n", mem_src);
538 [ # # ]: 0 : if (id != id_count)
539 : 0 : ERR_RETURN("Error with %s rte_dma_completed: incorrect job id received, %u [expected %u]\n",
540 : : mem_src, id, id_count);
541 : 0 : id_count++;
542 : :
543 [ # # ]: 0 : for (i = 0; i < len; i++)
544 [ # # ]: 0 : if (dst[i] != src[i])
545 : 0 : ERR_RETURN("Error with %s data mismatch at char %u [Got %02x not %02x]\n",
546 : : mem_src, i, dst[i], src[i]);
547 : :
548 : : return 0;
549 : : }
550 : :
551 : : static int
552 : 0 : test_enqueue_sva_copies(int16_t dev_id, uint16_t vchan)
553 : : {
554 : : char src[COPY_LEN], dst[COPY_LEN];
555 : : char *src_data, *dst_data;
556 : : int ret;
557 : :
558 : : /* test copy between buffer which malloced by libc. */
559 : 0 : src_data = malloc(COPY_LEN);
560 : 0 : dst_data = malloc(COPY_LEN);
561 [ # # ]: 0 : if (src_data == NULL || dst_data == NULL) {
562 : 0 : free(src_data);
563 : 0 : free(dst_data);
564 : 0 : ERR_RETURN("Error with malloc copy buffer!\n");
565 : : }
566 : 0 : ret = test_single_sva_copy(dev_id, vchan, "libc", src_data, dst_data, COPY_LEN);
567 : 0 : free(src_data);
568 : 0 : free(dst_data);
569 [ # # ]: 0 : if (ret != 0)
570 : : return ret;
571 : :
572 : : /* test copy between buffer which belong stack. */
573 : 0 : return test_single_sva_copy(dev_id, vchan, "stack", src, dst, COPY_LEN);
574 : : }
575 : :
576 : : /* Failure handling test cases - global macros and variables for those tests*/
577 : : #define COMP_BURST_SZ 16
578 : : #define OPT_FENCE(idx) ((fence && idx == 8) ? RTE_DMA_OP_FLAG_FENCE : 0)
579 : :
580 : : static int
581 : 0 : test_failure_in_full_burst(int16_t dev_id, uint16_t vchan, bool fence,
582 : : struct rte_mbuf **srcs, struct rte_mbuf **dsts, unsigned int fail_idx)
583 : : {
584 : : /* Test single full batch statuses with failures */
585 : : enum rte_dma_status_code status[COMP_BURST_SZ];
586 : : struct rte_dma_stats baseline, stats;
587 : : uint16_t invalid_addr_id = 0;
588 : : uint16_t idx;
589 : : uint16_t count, status_count;
590 : : unsigned int i;
591 : 0 : bool error = false;
592 : : int err_count = 0;
593 : :
594 : 0 : rte_dma_stats_get(dev_id, vchan, &baseline); /* get a baseline set of stats */
595 [ # # ]: 0 : for (i = 0; i < COMP_BURST_SZ; i++) {
596 : 0 : int id = rte_dma_copy(dev_id, vchan,
597 : 0 : (i == fail_idx ? 0 : rte_mbuf_data_iova(srcs[i])),
598 [ # # # # ]: 0 : rte_mbuf_data_iova(dsts[i]), COPY_LEN, OPT_FENCE(i));
599 [ # # ]: 0 : if (id < 0)
600 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", i);
601 [ # # ]: 0 : if (i == fail_idx)
602 : 0 : invalid_addr_id = id;
603 : : }
604 : : rte_dma_submit(dev_id, vchan);
605 : 0 : rte_dma_stats_get(dev_id, vchan, &stats);
606 [ # # ]: 0 : if (stats.submitted != baseline.submitted + COMP_BURST_SZ)
607 : 0 : ERR_RETURN("Submitted stats value not as expected, %"PRIu64" not %"PRIu64"\n",
608 : : stats.submitted, baseline.submitted + COMP_BURST_SZ);
609 : :
610 : 0 : await_hw(dev_id, vchan);
611 : :
612 : : count = rte_dma_completed(dev_id, vchan, COMP_BURST_SZ, &idx, &error);
613 [ # # ]: 0 : if (count != fail_idx)
614 : 0 : ERR_RETURN("Error with rte_dma_completed for failure test. Got returned %u not %u.\n",
615 : : count, fail_idx);
616 [ # # ]: 0 : if (!error)
617 : 0 : ERR_RETURN("Error, missing expected failed copy, %u. has_error is not set\n",
618 : : fail_idx);
619 [ # # ]: 0 : if (idx != invalid_addr_id - 1)
620 : 0 : ERR_RETURN("Error, missing expected failed copy, %u. Got last idx %u, not %u\n",
621 : : fail_idx, idx, invalid_addr_id - 1);
622 : :
623 : : /* all checks ok, now verify calling completed() again always returns 0 */
624 [ # # ]: 0 : for (i = 0; i < 10; i++)
625 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, COMP_BURST_SZ, &idx, &error) != 0
626 [ # # # # ]: 0 : || error == false || idx != (invalid_addr_id - 1))
627 : 0 : ERR_RETURN("Error with follow-up completed calls for fail idx %u\n",
628 : : fail_idx);
629 : :
630 : : status_count = rte_dma_completed_status(dev_id, vchan, COMP_BURST_SZ,
631 : : &idx, status);
632 : : /* some HW may stop on error and be restarted after getting error status for single value
633 : : * To handle this case, if we get just one error back, wait for more completions and get
634 : : * status for rest of the burst
635 : : */
636 [ # # ]: 0 : if (status_count == 1) {
637 : 0 : await_hw(dev_id, vchan);
638 : 0 : status_count += rte_dma_completed_status(dev_id, vchan, COMP_BURST_SZ - 1,
639 : : &idx, &status[1]);
640 : : }
641 : : /* check that at this point we have all status values */
642 [ # # ]: 0 : if (status_count != COMP_BURST_SZ - count)
643 : 0 : ERR_RETURN("Error with completed_status calls for fail idx %u. Got %u not %u\n",
644 : : fail_idx, status_count, COMP_BURST_SZ - count);
645 : : /* now verify just one failure followed by multiple successful or skipped entries */
646 [ # # ]: 0 : if (status[0] == RTE_DMA_STATUS_SUCCESSFUL)
647 : 0 : ERR_RETURN("Error with status returned for fail idx %u. First status was not failure\n",
648 : : fail_idx);
649 [ # # ]: 0 : for (i = 1; i < status_count; i++)
650 : : /* after a failure in a burst, depending on ordering/fencing,
651 : : * operations may be successful or skipped because of previous error.
652 : : */
653 : 0 : if (status[i] != RTE_DMA_STATUS_SUCCESSFUL
654 [ # # ]: 0 : && status[i] != RTE_DMA_STATUS_NOT_ATTEMPTED)
655 : 0 : ERR_RETURN("Error with status calls for fail idx %u. Status for job %u (of %u) is not successful\n",
656 : : fail_idx, count + i, COMP_BURST_SZ);
657 : :
658 : : /* check the completed + errors stats are as expected */
659 : 0 : rte_dma_stats_get(dev_id, vchan, &stats);
660 [ # # ]: 0 : if (stats.completed != baseline.completed + COMP_BURST_SZ)
661 : 0 : ERR_RETURN("Completed stats value not as expected, %"PRIu64" not %"PRIu64"\n",
662 : : stats.completed, baseline.completed + COMP_BURST_SZ);
663 [ # # ]: 0 : for (i = 0; i < status_count; i++)
664 : 0 : err_count += (status[i] != RTE_DMA_STATUS_SUCCESSFUL);
665 [ # # ]: 0 : if (stats.errors != baseline.errors + err_count)
666 : 0 : ERR_RETURN("'Errors' stats value not as expected, %"PRIu64" not %"PRIu64"\n",
667 : : stats.errors, baseline.errors + err_count);
668 : :
669 : : return 0;
670 : : }
671 : :
672 : : static int
673 : 0 : test_individual_status_query_with_failure(int16_t dev_id, uint16_t vchan, bool fence,
674 : : struct rte_mbuf **srcs, struct rte_mbuf **dsts, unsigned int fail_idx)
675 : : {
676 : : /* Test gathering batch statuses one at a time */
677 : : enum rte_dma_status_code status[COMP_BURST_SZ];
678 : : uint16_t invalid_addr_id = 0;
679 : : uint16_t idx;
680 : : uint16_t count = 0, status_count = 0;
681 : : unsigned int j;
682 : 0 : bool error = false;
683 : :
684 [ # # ]: 0 : for (j = 0; j < COMP_BURST_SZ; j++) {
685 : 0 : int id = rte_dma_copy(dev_id, vchan,
686 : 0 : (j == fail_idx ? 0 : rte_mbuf_data_iova(srcs[j])),
687 [ # # # # ]: 0 : rte_mbuf_data_iova(dsts[j]), COPY_LEN, OPT_FENCE(j));
688 [ # # ]: 0 : if (id < 0)
689 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", j);
690 [ # # ]: 0 : if (j == fail_idx)
691 : 0 : invalid_addr_id = id;
692 : : }
693 : 0 : rte_dma_submit(dev_id, vchan);
694 : 0 : await_hw(dev_id, vchan);
695 : :
696 : : /* use regular "completed" until we hit error */
697 [ # # ]: 0 : while (!error) {
698 : : uint16_t n = rte_dma_completed(dev_id, vchan, 1, &idx, &error);
699 : 0 : count += n;
700 [ # # ]: 0 : if (n > 1 || count >= COMP_BURST_SZ)
701 : 0 : ERR_RETURN("Error - too many completions got\n");
702 [ # # # # ]: 0 : if (n == 0 && !error)
703 : 0 : ERR_RETURN("Error, unexpectedly got zero completions after %u completed\n",
704 : : count);
705 : : }
706 [ # # ]: 0 : if (idx != invalid_addr_id - 1)
707 : 0 : ERR_RETURN("Error, last successful index not as expected, got %u, expected %u\n",
708 : : idx, invalid_addr_id - 1);
709 : :
710 : : /* use completed_status until we hit end of burst */
711 [ # # ]: 0 : while (count + status_count < COMP_BURST_SZ) {
712 : 0 : uint16_t n = rte_dma_completed_status(dev_id, vchan, 1, &idx,
713 : : &status[status_count]);
714 : 0 : await_hw(dev_id, vchan); /* allow delay to ensure jobs are completed */
715 : 0 : status_count += n;
716 [ # # ]: 0 : if (n != 1)
717 : 0 : ERR_RETURN("Error: unexpected number of completions received, %u, not 1\n",
718 : : n);
719 : : }
720 : :
721 : : /* check for single failure */
722 [ # # ]: 0 : if (status[0] == RTE_DMA_STATUS_SUCCESSFUL)
723 : 0 : ERR_RETURN("Error, unexpected successful DMA transaction\n");
724 [ # # ]: 0 : for (j = 1; j < status_count; j++)
725 : 0 : if (status[j] != RTE_DMA_STATUS_SUCCESSFUL
726 [ # # ]: 0 : && status[j] != RTE_DMA_STATUS_NOT_ATTEMPTED)
727 : 0 : ERR_RETURN("Error, unexpected DMA error reported\n");
728 : :
729 : : return 0;
730 : : }
731 : :
732 : : static int
733 : 0 : test_single_item_status_query_with_failure(int16_t dev_id, uint16_t vchan,
734 : : struct rte_mbuf **srcs, struct rte_mbuf **dsts, unsigned int fail_idx)
735 : : {
736 : : /* When error occurs just collect a single error using "completed_status()"
737 : : * before going to back to completed() calls
738 : : */
739 : : enum rte_dma_status_code status;
740 : : uint16_t invalid_addr_id = 0;
741 : : uint16_t idx;
742 : : uint16_t count, status_count, count2;
743 : : unsigned int j;
744 : 0 : bool error = false;
745 : :
746 [ # # ]: 0 : for (j = 0; j < COMP_BURST_SZ; j++) {
747 : 0 : int id = rte_dma_copy(dev_id, vchan,
748 : 0 : (j == fail_idx ? 0 : rte_mbuf_data_iova(srcs[j])),
749 [ # # ]: 0 : rte_mbuf_data_iova(dsts[j]), COPY_LEN, 0);
750 [ # # ]: 0 : if (id < 0)
751 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", j);
752 [ # # ]: 0 : if (j == fail_idx)
753 : 0 : invalid_addr_id = id;
754 : : }
755 : 0 : rte_dma_submit(dev_id, vchan);
756 : 0 : await_hw(dev_id, vchan);
757 : :
758 : : /* get up to the error point */
759 : : count = rte_dma_completed(dev_id, vchan, COMP_BURST_SZ, &idx, &error);
760 [ # # ]: 0 : if (count != fail_idx)
761 : 0 : ERR_RETURN("Error with rte_dma_completed for failure test. Got returned %u not %u.\n",
762 : : count, fail_idx);
763 [ # # ]: 0 : if (!error)
764 : 0 : ERR_RETURN("Error, missing expected failed copy, %u. has_error is not set\n",
765 : : fail_idx);
766 [ # # ]: 0 : if (idx != invalid_addr_id - 1)
767 : 0 : ERR_RETURN("Error, missing expected failed copy, %u. Got last idx %u, not %u\n",
768 : : fail_idx, idx, invalid_addr_id - 1);
769 : :
770 : : /* get the error code */
771 : : status_count = rte_dma_completed_status(dev_id, vchan, 1, &idx, &status);
772 [ # # ]: 0 : if (status_count != 1)
773 : 0 : ERR_RETURN("Error with completed_status calls for fail idx %u. Got %u not %u\n",
774 : : fail_idx, status_count, COMP_BURST_SZ - count);
775 [ # # ]: 0 : if (status == RTE_DMA_STATUS_SUCCESSFUL)
776 : 0 : ERR_RETURN("Error with status returned for fail idx %u. First status was not failure\n",
777 : : fail_idx);
778 : :
779 : : /* delay in case time needed after err handled to complete other jobs */
780 : 0 : await_hw(dev_id, vchan);
781 : :
782 : : /* get the rest of the completions without status */
783 : : count2 = rte_dma_completed(dev_id, vchan, COMP_BURST_SZ, &idx, &error);
784 [ # # ]: 0 : if (error == true)
785 : 0 : ERR_RETURN("Error, got further errors post completed_status() call, for failure case %u.\n",
786 : : fail_idx);
787 [ # # ]: 0 : if (count + status_count + count2 != COMP_BURST_SZ)
788 : 0 : ERR_RETURN("Error, incorrect number of completions received, got %u not %u\n",
789 : : count + status_count + count2, COMP_BURST_SZ);
790 : :
791 : : return 0;
792 : : }
793 : :
794 : : static int
795 : 0 : test_multi_failure(int16_t dev_id, uint16_t vchan, struct rte_mbuf **srcs, struct rte_mbuf **dsts,
796 : : const unsigned int *fail, size_t num_fail)
797 : : {
798 : : /* test having multiple errors in one go */
799 : : enum rte_dma_status_code status[COMP_BURST_SZ];
800 : : unsigned int i, j;
801 : : uint16_t count, err_count = 0;
802 : 0 : bool error = false;
803 : :
804 : : /* enqueue and gather completions in one go */
805 [ # # ]: 0 : for (j = 0; j < COMP_BURST_SZ; j++) {
806 : 0 : uintptr_t src = rte_mbuf_data_iova(srcs[j]);
807 : : /* set up for failure if the current index is anywhere is the fails array */
808 [ # # ]: 0 : for (i = 0; i < num_fail; i++)
809 [ # # ]: 0 : if (j == fail[i])
810 : : src = 0;
811 : :
812 : 0 : int id = rte_dma_copy(dev_id, vchan, src, rte_mbuf_data_iova(dsts[j]),
813 : : COPY_LEN, 0);
814 [ # # ]: 0 : if (id < 0)
815 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", j);
816 : : }
817 : 0 : rte_dma_submit(dev_id, vchan);
818 : 0 : await_hw(dev_id, vchan);
819 : :
820 : : count = rte_dma_completed_status(dev_id, vchan, COMP_BURST_SZ, NULL, status);
821 [ # # ]: 0 : while (count < COMP_BURST_SZ) {
822 : 0 : await_hw(dev_id, vchan);
823 : :
824 : 0 : uint16_t ret = rte_dma_completed_status(dev_id, vchan, COMP_BURST_SZ - count,
825 : 0 : NULL, &status[count]);
826 [ # # ]: 0 : if (ret == 0)
827 : 0 : ERR_RETURN("Error getting all completions for jobs. Got %u of %u\n",
828 : : count, COMP_BURST_SZ);
829 : 0 : count += ret;
830 : : }
831 [ # # ]: 0 : for (i = 0; i < count; i++)
832 [ # # ]: 0 : if (status[i] != RTE_DMA_STATUS_SUCCESSFUL)
833 : 0 : err_count++;
834 : :
835 [ # # ]: 0 : if (err_count != num_fail)
836 : 0 : ERR_RETURN("Error: Invalid number of failed completions returned, %u; expected %zu\n",
837 : : err_count, num_fail);
838 : :
839 : : /* enqueue and gather completions in bursts, but getting errors one at a time */
840 [ # # ]: 0 : for (j = 0; j < COMP_BURST_SZ; j++) {
841 : 0 : uintptr_t src = rte_mbuf_data_iova(srcs[j]);
842 : : /* set up for failure if the current index is anywhere is the fails array */
843 [ # # ]: 0 : for (i = 0; i < num_fail; i++)
844 [ # # ]: 0 : if (j == fail[i])
845 : : src = 0;
846 : :
847 : 0 : int id = rte_dma_copy(dev_id, vchan, src, rte_mbuf_data_iova(dsts[j]),
848 : : COPY_LEN, 0);
849 [ # # ]: 0 : if (id < 0)
850 : 0 : ERR_RETURN("Error with rte_dma_copy for buffer %u\n", j);
851 : : }
852 : : rte_dma_submit(dev_id, vchan);
853 : 0 : await_hw(dev_id, vchan);
854 : :
855 : : count = 0;
856 : : err_count = 0;
857 [ # # ]: 0 : while (count + err_count < COMP_BURST_SZ) {
858 : 0 : count += rte_dma_completed(dev_id, vchan, COMP_BURST_SZ, NULL, &error);
859 [ # # ]: 0 : if (error) {
860 : : uint16_t ret = rte_dma_completed_status(dev_id, vchan, 1,
861 : : NULL, status);
862 [ # # ]: 0 : if (ret != 1)
863 : 0 : ERR_RETURN("Error getting error-status for completions\n");
864 : 0 : err_count += ret;
865 : 0 : await_hw(dev_id, vchan);
866 : : }
867 : : }
868 [ # # ]: 0 : if (err_count != num_fail)
869 : 0 : ERR_RETURN("Error: Incorrect number of failed completions received, got %u not %zu\n",
870 : : err_count, num_fail);
871 : :
872 : : return 0;
873 : : }
874 : :
875 : : static int
876 : 0 : test_completion_status(int16_t dev_id, uint16_t vchan, bool fence)
877 : : {
878 : 0 : const unsigned int fail[] = {0, 7, 14, 15};
879 : : struct rte_mbuf *srcs[COMP_BURST_SZ], *dsts[COMP_BURST_SZ];
880 : : unsigned int i;
881 : :
882 [ # # ]: 0 : for (i = 0; i < COMP_BURST_SZ; i++) {
883 : 0 : srcs[i] = rte_pktmbuf_alloc(pool);
884 : 0 : dsts[i] = rte_pktmbuf_alloc(pool);
885 : : }
886 : :
887 [ # # ]: 0 : for (i = 0; i < RTE_DIM(fail); i++) {
888 [ # # ]: 0 : if (test_failure_in_full_burst(dev_id, vchan, fence, srcs, dsts, fail[i]) < 0)
889 : : return -1;
890 : :
891 [ # # ]: 0 : if (test_individual_status_query_with_failure(dev_id, vchan, fence,
892 : : srcs, dsts, fail[i]) < 0)
893 : : return -1;
894 : :
895 : : /* test is run the same fenced, or unfenced, but no harm in running it twice */
896 [ # # ]: 0 : if (test_single_item_status_query_with_failure(dev_id, vchan,
897 : : srcs, dsts, fail[i]) < 0)
898 : : return -1;
899 : : }
900 : :
901 [ # # ]: 0 : if (test_multi_failure(dev_id, vchan, srcs, dsts, fail, RTE_DIM(fail)) < 0)
902 : : return -1;
903 : :
904 [ # # ]: 0 : for (i = 0; i < COMP_BURST_SZ; i++) {
905 : 0 : rte_pktmbuf_free(srcs[i]);
906 : 0 : rte_pktmbuf_free(dsts[i]);
907 : : }
908 : : return 0;
909 : : }
910 : :
911 : : static int
912 : 0 : test_completion_handling(int16_t dev_id, uint16_t vchan)
913 : : {
914 : 0 : return test_completion_status(dev_id, vchan, false) /* without fences */
915 [ # # # # ]: 0 : || test_completion_status(dev_id, vchan, true); /* with fences */
916 : : }
917 : :
918 : : static int
919 : 0 : test_enqueue_fill(int16_t dev_id, uint16_t vchan)
920 : : {
921 : 0 : const unsigned int lengths[] = {8, 64, 1024, 50, 100, 89};
922 : : struct rte_mbuf *dst;
923 : : char *dst_data;
924 : 0 : uint64_t pattern = 0xfedcba9876543210;
925 : : unsigned int i, j;
926 : :
927 : 0 : dst = rte_pktmbuf_alloc(pool);
928 [ # # ]: 0 : if (dst == NULL)
929 : 0 : ERR_RETURN("Failed to allocate mbuf\n");
930 : 0 : dst_data = rte_pktmbuf_mtod(dst, char *);
931 : :
932 [ # # ]: 0 : for (i = 0; i < RTE_DIM(lengths); i++) {
933 : : /* reset dst_data */
934 : 0 : memset(dst_data, 0, rte_pktmbuf_data_len(dst));
935 : :
936 : : /* perform the fill operation */
937 : 0 : int id = rte_dma_fill(dev_id, vchan, pattern,
938 : 0 : rte_pktmbuf_iova(dst), lengths[i], RTE_DMA_OP_FLAG_SUBMIT);
939 [ # # ]: 0 : if (id < 0)
940 : 0 : ERR_RETURN("Error with rte_dma_fill\n");
941 : 0 : await_hw(dev_id, vchan);
942 : :
943 [ # # ]: 0 : if (rte_dma_completed(dev_id, vchan, 1, NULL, NULL) != 1)
944 : 0 : ERR_RETURN("Error: fill operation failed (length: %u)\n", lengths[i]);
945 : : /* check the data from the fill operation is correct */
946 [ # # ]: 0 : for (j = 0; j < lengths[i]; j++) {
947 : 0 : char pat_byte = ((char *)&pattern)[j % 8];
948 [ # # ]: 0 : if (dst_data[j] != pat_byte)
949 : 0 : ERR_RETURN("Error with fill operation (lengths = %u): got (%x), not (%x)\n",
950 : : lengths[i], dst_data[j], pat_byte);
951 : : }
952 : : /* check that the data after the fill operation was not written to */
953 [ # # ]: 0 : for (; j < rte_pktmbuf_data_len(dst); j++)
954 [ # # ]: 0 : if (dst_data[j] != 0)
955 : 0 : ERR_RETURN("Error, fill operation wrote too far (lengths = %u): got (%x), not (%x)\n",
956 : : lengths[i], dst_data[j], 0);
957 : : }
958 : :
959 : 0 : rte_pktmbuf_free(dst);
960 : 0 : return 0;
961 : : }
962 : :
963 : : static int
964 : 0 : test_burst_capacity(int16_t dev_id, uint16_t vchan)
965 : : {
966 : : #define CAP_TEST_BURST_SIZE 64
967 : 0 : const int ring_space = rte_dma_burst_capacity(dev_id, vchan);
968 : : struct rte_mbuf *src, *dst;
969 : : int i, j, iter;
970 : : int cap, ret;
971 : : bool dma_err;
972 : :
973 : 0 : src = rte_pktmbuf_alloc(pool);
974 : 0 : dst = rte_pktmbuf_alloc(pool);
975 : :
976 : : /* to test capacity, we enqueue elements and check capacity is reduced
977 : : * by one each time - rebaselining the expected value after each burst
978 : : * as the capacity is only for a burst. We enqueue multiple bursts to
979 : : * fill up half the ring, before emptying it again. We do this multiple
980 : : * times to ensure that we get to test scenarios where we get ring
981 : : * wrap-around and wrap-around of the ids returned (at UINT16_MAX).
982 : : */
983 [ # # ]: 0 : for (iter = 0; iter < 2 * (((int)UINT16_MAX + 1) / ring_space); iter++) {
984 [ # # ]: 0 : for (i = 0; i < (ring_space / (2 * CAP_TEST_BURST_SIZE)) + 1; i++) {
985 : 0 : cap = rte_dma_burst_capacity(dev_id, vchan);
986 : :
987 [ # # ]: 0 : for (j = 0; j < CAP_TEST_BURST_SIZE; j++) {
988 : 0 : ret = rte_dma_copy(dev_id, vchan, rte_pktmbuf_iova(src),
989 : 0 : rte_pktmbuf_iova(dst), COPY_LEN, 0);
990 [ # # ]: 0 : if (ret < 0)
991 : 0 : ERR_RETURN("Error with rte_dmadev_copy\n");
992 : :
993 [ # # ]: 0 : if (rte_dma_burst_capacity(dev_id, vchan) != cap - (j + 1))
994 : 0 : ERR_RETURN("Error, ring capacity did not change as expected\n");
995 : : }
996 [ # # ]: 0 : if (rte_dma_submit(dev_id, vchan) < 0)
997 : 0 : ERR_RETURN("Error, failed to submit burst\n");
998 : :
999 [ # # ]: 0 : if (cap < rte_dma_burst_capacity(dev_id, vchan))
1000 : 0 : ERR_RETURN("Error, avail ring capacity has gone up, not down\n");
1001 : : }
1002 : 0 : await_hw(dev_id, vchan);
1003 : :
1004 [ # # ]: 0 : for (i = 0; i < (ring_space / (2 * CAP_TEST_BURST_SIZE)) + 1; i++) {
1005 : 0 : ret = rte_dma_completed(dev_id, vchan,
1006 : : CAP_TEST_BURST_SIZE, NULL, &dma_err);
1007 [ # # # # ]: 0 : if (ret != CAP_TEST_BURST_SIZE || dma_err) {
1008 : : enum rte_dma_status_code status;
1009 : :
1010 : : rte_dma_completed_status(dev_id, vchan, 1, NULL, &status);
1011 : 0 : ERR_RETURN("Error with rte_dmadev_completed, %u [expected: %u], dma_err = %d, i = %u, iter = %u, status = %u\n",
1012 : : ret, CAP_TEST_BURST_SIZE, dma_err, i, iter, status);
1013 : : }
1014 : : }
1015 : 0 : cap = rte_dma_burst_capacity(dev_id, vchan);
1016 [ # # ]: 0 : if (cap != ring_space)
1017 : 0 : ERR_RETURN("Error, ring capacity has not reset to original value, got %u, expected %u\n",
1018 : : cap, ring_space);
1019 : : }
1020 : :
1021 : 0 : rte_pktmbuf_free(src);
1022 : 0 : rte_pktmbuf_free(dst);
1023 : :
1024 : 0 : return 0;
1025 : : }
1026 : :
1027 : : static int
1028 : 0 : test_m2d_auto_free(int16_t dev_id, uint16_t vchan)
1029 : : {
1030 : : #define NR_MBUF 256
1031 : : struct rte_mempool_cache *cache;
1032 : : struct rte_mbuf *src[NR_MBUF];
1033 : : uint32_t buf_cnt1, buf_cnt2;
1034 : : struct rte_mempool_ops *ops;
1035 : : uint16_t nb_done = 0;
1036 : 0 : bool dma_err = false;
1037 : : int retry = 100;
1038 : : int i, ret = 0;
1039 : : rte_iova_t dst;
1040 : :
1041 [ # # ]: 0 : dst = (rte_iova_t)env_test_param[TEST_PARAM_REMOTE_ADDR];
1042 : :
1043 : : /* Capture buffer count before allocating source buffer. */
1044 [ # # ]: 0 : cache = rte_mempool_default_cache(pool, rte_lcore_id());
1045 : 0 : ops = rte_mempool_get_ops(pool->ops_index);
1046 : 0 : buf_cnt1 = ops->get_count(pool) + cache->len;
1047 : :
1048 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(pool, src, NR_MBUF) != 0)
1049 : 0 : ERR_RETURN("alloc src mbufs failed.\n");
1050 : :
1051 [ # # ]: 0 : if ((buf_cnt1 - NR_MBUF) != (ops->get_count(pool) + cache->len)) {
1052 : : printf("Buffer count check failed.\n");
1053 : : ret = -1;
1054 : 0 : goto done;
1055 : : }
1056 : :
1057 [ # # ]: 0 : for (i = 0; i < NR_MBUF; i++) {
1058 : 0 : ret = rte_dma_copy(dev_id, vchan, rte_mbuf_data_iova(src[i]), dst,
1059 : : COPY_LEN, RTE_DMA_OP_FLAG_AUTO_FREE);
1060 : :
1061 [ # # ]: 0 : if (ret < 0) {
1062 : : printf("rte_dma_copy returned error.\n");
1063 : 0 : goto done;
1064 : : }
1065 : : }
1066 : :
1067 : 0 : rte_dma_submit(dev_id, vchan);
1068 : : do {
1069 : 0 : nb_done += rte_dma_completed(dev_id, vchan, (NR_MBUF - nb_done), NULL, &dma_err);
1070 [ # # ]: 0 : if (dma_err)
1071 : : break;
1072 : : /* Sleep for 1 millisecond */
1073 : 0 : rte_delay_us_sleep(1000);
1074 [ # # # # ]: 0 : } while (retry-- && (nb_done < NR_MBUF));
1075 : :
1076 : 0 : buf_cnt2 = ops->get_count(pool) + cache->len;
1077 [ # # # # ]: 0 : if ((buf_cnt1 != buf_cnt2) || dma_err) {
1078 : : printf("Free mem to dev buffer test failed.\n");
1079 : : ret = -1;
1080 : : }
1081 : :
1082 : 0 : done:
1083 : : /* If the test passes source buffer will be freed in hardware. */
1084 [ # # ]: 0 : if (ret < 0)
1085 : 0 : rte_pktmbuf_free_bulk(&src[nb_done], (NR_MBUF - nb_done));
1086 : :
1087 : : return ret;
1088 : : }
1089 : :
1090 : : static int
1091 : 0 : prepare_m2d_auto_free(int16_t dev_id, uint16_t vchan)
1092 : : {
1093 : 0 : const struct rte_dma_vchan_conf qconf = {
1094 : : .direction = RTE_DMA_DIR_MEM_TO_DEV,
1095 : : .nb_desc = TEST_RINGSIZE,
1096 : : .auto_free.m2d.pool = pool,
1097 : : .dst_port.port_type = RTE_DMA_PORT_PCIE,
1098 : : .dst_port.pcie.coreid = 0,
1099 : : };
1100 : :
1101 : : /* Stop the device to reconfigure vchan. */
1102 [ # # ]: 0 : if (rte_dma_stop(dev_id) < 0)
1103 : 0 : ERR_RETURN("Error stopping device %u\n", dev_id);
1104 : :
1105 [ # # ]: 0 : if (rte_dma_vchan_setup(dev_id, vchan, &qconf) < 0)
1106 : 0 : ERR_RETURN("Error with queue configuration\n");
1107 : :
1108 [ # # ]: 0 : if (rte_dma_start(dev_id) != 0)
1109 : 0 : ERR_RETURN("Error with rte_dma_start()\n");
1110 : :
1111 : : return 0;
1112 : : }
1113 : :
1114 : : static int
1115 : 0 : test_enq_deq_ops(int16_t dev_id, uint16_t vchan)
1116 : : {
1117 : : #define BURST_SIZE 16
1118 : : #define ROUNDS 2E7
1119 : : #define CPY_LEN 64
1120 : : struct rte_mempool *ops_pool, *pkt_pool;
1121 : : struct rte_mbuf *mbufs[BURST_SIZE * 2];
1122 : : struct rte_dma_op *ops[BURST_SIZE];
1123 : : uint64_t enq_lat, deq_lat, start;
1124 : : int ret, i, j, enq, deq, n, max;
1125 : : struct rte_dma_sge ssg, dsg;
1126 : : struct rte_dma_info info;
1127 : : uint64_t tenq, tdeq;
1128 : :
1129 : : memset(&info, 0, sizeof(info));
1130 : 0 : ret = rte_dma_info_get(dev_id, &info);
1131 [ # # ]: 0 : if (ret != 0)
1132 : 0 : ERR_RETURN("Error with rte_dma_info_get()\n");
1133 : :
1134 : 0 : pkt_pool = rte_pktmbuf_pool_create("pkt_pool", info.max_desc * 2, 0, 0,
1135 : 0 : CPY_LEN + RTE_PKTMBUF_HEADROOM, rte_socket_id());
1136 [ # # ]: 0 : if (pkt_pool == NULL)
1137 : 0 : ERR_RETURN("Error creating pkt pool\n");
1138 : :
1139 : 0 : ops_pool = rte_mempool_create("ops_pool", info.max_desc,
1140 : : sizeof(struct rte_dma_op) + (sizeof(struct rte_dma_sge) * 2),
1141 : 0 : 0, 0, NULL, NULL, NULL, NULL, rte_socket_id(), 0);
1142 [ # # ]: 0 : if (ops_pool == NULL)
1143 : 0 : ERR_RETURN("Error creating ops pool\n");
1144 : :
1145 : 0 : max = info.max_desc - BURST_SIZE;
1146 : : tenq = 0;
1147 : : tdeq = 0;
1148 : : enq_lat = 0;
1149 : : deq_lat = 0;
1150 : :
1151 [ # # ]: 0 : for (i = 0; i < ROUNDS / max; i++) {
1152 : : n = 0;
1153 [ # # ]: 0 : while (n != max) {
1154 [ # # ]: 0 : if (rte_mempool_get_bulk(ops_pool, (void **)ops, BURST_SIZE) != 0)
1155 : 0 : continue;
1156 : :
1157 [ # # ]: 0 : if (rte_pktmbuf_alloc_bulk(pkt_pool, mbufs, BURST_SIZE * 2) != 0)
1158 : 0 : ERR_RETURN("Error allocating mbufs %d\n", n);
1159 : :
1160 [ # # ]: 0 : for (j = 0; j < BURST_SIZE; j++) {
1161 : 0 : ops[j]->src_dst_seg[0].addr = rte_pktmbuf_iova(mbufs[j]);
1162 : 0 : ops[j]->src_dst_seg[1].addr =
1163 : 0 : rte_pktmbuf_iova(mbufs[j + BURST_SIZE]);
1164 : 0 : ops[j]->src_dst_seg[0].length = CPY_LEN;
1165 : 0 : ops[j]->src_dst_seg[1].length = CPY_LEN;
1166 : :
1167 : 0 : ops[j]->nb_src = 1;
1168 : 0 : ops[j]->nb_dst = 1;
1169 : 0 : ops[j]->user_meta = (uint64_t)mbufs[j];
1170 : 0 : ops[j]->event_meta = (uint64_t)mbufs[j + BURST_SIZE];
1171 : :
1172 : 0 : memset((void *)(uintptr_t)ops[j]->src_dst_seg[0].addr,
1173 : 0 : rte_rand() & 0xFF, CPY_LEN);
1174 : 0 : memset((void *)(uintptr_t)ops[j]->src_dst_seg[1].addr, 0, CPY_LEN);
1175 : : }
1176 : :
1177 : : start = rte_rdtsc_precise();
1178 : 0 : enq = rte_dma_enqueue_ops(dev_id, vchan, ops, BURST_SIZE);
1179 [ # # ]: 0 : while (enq != BURST_SIZE) {
1180 : 0 : enq += rte_dma_enqueue_ops(dev_id, vchan, ops + enq,
1181 : 0 : BURST_SIZE - enq);
1182 : : }
1183 : :
1184 : 0 : enq_lat += rte_rdtsc_precise() - start;
1185 : 0 : n += enq;
1186 : : }
1187 : 0 : tenq += n;
1188 : :
1189 : : memset(ops, 0, sizeof(ops));
1190 : : n = 0;
1191 [ # # ]: 0 : while (n != max) {
1192 : : start = rte_rdtsc_precise();
1193 : 0 : deq = rte_dma_dequeue_ops(dev_id, vchan, ops, BURST_SIZE);
1194 [ # # ]: 0 : while (deq != BURST_SIZE) {
1195 : 0 : deq += rte_dma_dequeue_ops(dev_id, vchan, ops + deq,
1196 : 0 : BURST_SIZE - deq);
1197 : : }
1198 : 0 : n += deq;
1199 : 0 : deq_lat += rte_rdtsc_precise() - start;
1200 : :
1201 [ # # ]: 0 : for (j = 0; j < deq; j++) {
1202 : : /* check the data is correct */
1203 : 0 : ssg = ops[j]->src_dst_seg[0];
1204 : 0 : dsg = ops[j]->src_dst_seg[1];
1205 [ # # ]: 0 : if (memcmp((void *)(uintptr_t)ssg.addr, (void *)(uintptr_t)dsg.addr,
1206 : : ssg.length) != 0)
1207 : 0 : ERR_RETURN("Error with copy operation\n");
1208 : 0 : rte_pktmbuf_free((struct rte_mbuf *)(uintptr_t)ops[j]->user_meta);
1209 : 0 : rte_pktmbuf_free((struct rte_mbuf *)(uintptr_t)ops[j]->event_meta);
1210 : : }
1211 : : rte_mempool_put_bulk(ops_pool, (void **)ops, BURST_SIZE);
1212 : : }
1213 : 0 : tdeq += n;
1214 : :
1215 : 0 : printf("\rEnqueued %" PRIu64 " Latency %.3f Dequeued %" PRIu64 " Latency %.3f",
1216 : 0 : tenq, (double)enq_lat / tenq, tdeq, (double)deq_lat / tdeq);
1217 : : }
1218 : : printf("\n");
1219 : :
1220 : 0 : rte_mempool_free(pkt_pool);
1221 : 0 : rte_mempool_free(ops_pool);
1222 : :
1223 : 0 : return 0;
1224 : : }
1225 : :
1226 : : static int
1227 : 0 : prepare_enq_deq_ops(int16_t dev_id, uint16_t vchan)
1228 : : {
1229 : 0 : const struct rte_dma_conf conf = {.nb_vchans = 1, .flags = RTE_DMA_CFG_FLAG_ENQ_DEQ};
1230 : : struct rte_dma_vchan_conf qconf;
1231 : : struct rte_dma_info info;
1232 : :
1233 : : memset(&qconf, 0, sizeof(qconf));
1234 : : memset(&info, 0, sizeof(info));
1235 : :
1236 : 0 : int ret = rte_dma_info_get(dev_id, &info);
1237 [ # # ]: 0 : if (ret != 0)
1238 : 0 : ERR_RETURN("Error with rte_dma_info_get()\n");
1239 : :
1240 : 0 : qconf.direction = RTE_DMA_DIR_MEM_TO_MEM;
1241 : 0 : qconf.nb_desc = info.max_desc;
1242 : :
1243 [ # # ]: 0 : if (rte_dma_stop(dev_id) < 0)
1244 : 0 : ERR_RETURN("Error stopping device %u\n", dev_id);
1245 [ # # ]: 0 : if (rte_dma_configure(dev_id, &conf) != 0)
1246 : 0 : ERR_RETURN("Error with rte_dma_configure()\n");
1247 [ # # ]: 0 : if (rte_dma_vchan_setup(dev_id, vchan, &qconf) < 0)
1248 : 0 : ERR_RETURN("Error with queue configuration\n");
1249 [ # # ]: 0 : if (rte_dma_start(dev_id) != 0)
1250 : 0 : ERR_RETURN("Error with rte_dma_start()\n");
1251 : :
1252 : : return 0;
1253 : : }
1254 : :
1255 : : static int
1256 : 0 : test_dmadev_sg_copy_setup(void)
1257 : : {
1258 : : int ret = TEST_SUCCESS;
1259 : :
1260 [ # # ]: 0 : if ((info.dev_capa & RTE_DMA_CAPA_OPS_COPY_SG) == 0)
1261 : 0 : return TEST_SKIPPED;
1262 : :
1263 : : return ret;
1264 : : }
1265 : :
1266 : : static int
1267 : 0 : test_dmadev_sva_setup(void)
1268 : : {
1269 : : int ret = TEST_SUCCESS;
1270 : :
1271 [ # # ]: 0 : if ((info.dev_capa & RTE_DMA_CAPA_SVA) == 0) {
1272 : 0 : RTE_LOG(ERR, USER1,
1273 : : "DMA Dev %u: device does not support SVA, skipping SVA tests\n",
1274 : : test_dev_id);
1275 : : ret = TEST_SKIPPED;
1276 : : }
1277 : :
1278 : 0 : return ret;
1279 : : }
1280 : :
1281 : : static int
1282 : 0 : test_dmadev_burst_setup(void)
1283 : : {
1284 [ # # ]: 0 : if (rte_dma_burst_capacity(test_dev_id, vchan) < 64) {
1285 : 0 : RTE_LOG(ERR, USER1,
1286 : : "DMA Dev %u: insufficient burst capacity (64 required), skipping tests\n",
1287 : : test_dev_id);
1288 : 0 : return TEST_SKIPPED;
1289 : : }
1290 : :
1291 : : return TEST_SUCCESS;
1292 : : }
1293 : :
1294 : : static int
1295 : 0 : test_dmadev_err_handling_setup(void)
1296 : : {
1297 : : int ret = TEST_SKIPPED;
1298 : :
1299 : : /* to test error handling we can provide null pointers for source or dest in copies. This
1300 : : * requires VA mode in DPDK, since NULL(0) is a valid physical address.
1301 : : * We also need hardware that can report errors back.
1302 : : */
1303 [ # # ]: 0 : if (rte_eal_iova_mode() != RTE_IOVA_VA)
1304 : 0 : RTE_LOG(ERR, USER1,
1305 : : "DMA Dev %u: DPDK not in VA mode, skipping error handling tests\n",
1306 : : test_dev_id);
1307 [ # # ]: 0 : else if ((info.dev_capa & RTE_DMA_CAPA_HANDLES_ERRORS) == 0)
1308 : 0 : RTE_LOG(ERR, USER1,
1309 : : "DMA Dev %u: device does not report errors, skipping error handling tests\n",
1310 : : test_dev_id);
1311 : : else
1312 : : ret = TEST_SUCCESS;
1313 : :
1314 : 0 : return ret;
1315 : : }
1316 : :
1317 : : static int
1318 : 0 : test_dmadev_fill_setup(void)
1319 : : {
1320 : : int ret = TEST_SUCCESS;
1321 : :
1322 [ # # ]: 0 : if ((info.dev_capa & RTE_DMA_CAPA_OPS_FILL) == 0) {
1323 : 0 : RTE_LOG(ERR, USER1,
1324 : : "DMA Dev %u: No device fill support, skipping fill tests\n", test_dev_id);
1325 : : ret = TEST_SKIPPED;
1326 : : }
1327 : :
1328 : 0 : return ret;
1329 : : }
1330 : :
1331 : : static int
1332 : 0 : test_dmadev_autofree_setup(void)
1333 : : {
1334 : : int ret = TEST_SKIPPED;
1335 : :
1336 [ # # ]: 0 : if ((info.dev_capa & RTE_DMA_CAPA_M2D_AUTO_FREE) &&
1337 [ # # ]: 0 : dma_add_test[TEST_M2D_AUTO_FREE].enabled == true) {
1338 [ # # ]: 0 : if (prepare_m2d_auto_free(test_dev_id, vchan) != 0)
1339 : 0 : return ret;
1340 : :
1341 : : ret = TEST_SUCCESS;
1342 : : }
1343 : :
1344 : : return ret;
1345 : : }
1346 : :
1347 : : static int
1348 : 0 : test_dmadev_enq_deq_setup(void)
1349 : : {
1350 : : int ret = TEST_SKIPPED;
1351 : :
1352 [ # # ]: 0 : if ((info.dev_capa & RTE_DMA_CAPA_OPS_ENQ_DEQ)) {
1353 [ # # ]: 0 : if (prepare_enq_deq_ops(test_dev_id, vchan) != 0)
1354 : 0 : return ret;
1355 : : ret = TEST_SUCCESS;
1356 : : }
1357 : :
1358 : : return ret;
1359 : : }
1360 : :
1361 : : static int
1362 : 0 : test_dmadev_setup(void)
1363 : : {
1364 : 0 : int16_t dev_id = test_dev_id;
1365 : : struct rte_dma_stats stats;
1366 : 0 : const struct rte_dma_conf conf = { .nb_vchans = 1};
1367 : 0 : struct rte_dma_vchan_conf qconf = {
1368 : : .direction = RTE_DMA_DIR_MEM_TO_MEM,
1369 : : .nb_desc = TEST_RINGSIZE,
1370 : : };
1371 : : int ret;
1372 : :
1373 : 0 : ret = rte_dma_info_get(dev_id, &info);
1374 [ # # ]: 0 : if (ret != 0)
1375 : 0 : ERR_RETURN("Error with rte_dma_info_get()\n");
1376 : :
1377 [ # # ]: 0 : if (info.max_vchans < 1)
1378 : 0 : ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
1379 : :
1380 [ # # ]: 0 : if (rte_dma_configure(dev_id, &conf) != 0)
1381 : 0 : ERR_RETURN("Error with rte_dma_configure()\n");
1382 : :
1383 [ # # ]: 0 : if (qconf.nb_desc < info.min_desc)
1384 : 0 : qconf.nb_desc = info.min_desc;
1385 [ # # ]: 0 : if (qconf.nb_desc > info.max_desc)
1386 : 0 : qconf.nb_desc = info.max_desc;
1387 [ # # ]: 0 : if (rte_dma_vchan_setup(dev_id, vchan, &qconf) < 0)
1388 : 0 : ERR_RETURN("Error with queue configuration\n");
1389 : :
1390 : 0 : ret = rte_dma_info_get(dev_id, &info);
1391 [ # # # # ]: 0 : if (ret != 0 || info.nb_vchans != 1)
1392 : 0 : ERR_RETURN("Error, no configured queues reported on device id %u\n", dev_id);
1393 : :
1394 [ # # ]: 0 : if (rte_dma_start(dev_id) != 0)
1395 : 0 : ERR_RETURN("Error with rte_dma_start()\n");
1396 : :
1397 [ # # ]: 0 : if (rte_dma_stats_get(dev_id, vchan, &stats) != 0)
1398 : 0 : ERR_RETURN("Error with rte_dma_stats_get()\n");
1399 : :
1400 [ # # ]: 0 : if (rte_dma_burst_capacity(dev_id, vchan) < 32)
1401 : 0 : ERR_RETURN("Error: Device does not have sufficient burst capacity to run tests");
1402 : :
1403 [ # # # # : 0 : if (stats.completed != 0 || stats.submitted != 0 || stats.errors != 0)
# # ]
1404 : 0 : ERR_RETURN("Error device stats are not all zero: completed = %"PRIu64", "
1405 : : "submitted = %"PRIu64", errors = %"PRIu64"\n",
1406 : : stats.completed, stats.submitted, stats.errors);
1407 : 0 : id_count = 0;
1408 : :
1409 : : /* create a mempool for running tests */
1410 : 0 : pool = rte_pktmbuf_pool_create("TEST_DMADEV_POOL",
1411 : : TEST_RINGSIZE * 2, /* n == num elements */
1412 : : 32, /* cache size */
1413 : : 0, /* priv size */
1414 : : COPY_LEN + RTE_PKTMBUF_HEADROOM, /* data room size */
1415 : 0 : info.numa_node);
1416 [ # # ]: 0 : if (pool == NULL)
1417 : 0 : ERR_RETURN("Error with mempool creation\n");
1418 : :
1419 : 0 : check_err_stats = false;
1420 : 0 : vchan = 0;
1421 : :
1422 : 0 : return 0;
1423 : : }
1424 : :
1425 : : static void
1426 : 0 : test_dmadev_teardown(void)
1427 : : {
1428 : 0 : rte_mempool_free(pool);
1429 : 0 : rte_dma_stop(test_dev_id);
1430 : 0 : rte_dma_stats_reset(test_dev_id, vchan);
1431 : 0 : test_dev_id = -EINVAL;
1432 : 0 : }
1433 : :
1434 : : static int
1435 : 0 : test_dmadev_instance(int16_t dev_id)
1436 : : {
1437 : : struct rte_dma_info dev_info;
1438 : : enum {
1439 : : TEST_COPY = 0,
1440 : : TEST_COPY_SG,
1441 : : TEST_SVA_COPY,
1442 : : TEST_START,
1443 : : TEST_BURST,
1444 : : TEST_ERR,
1445 : : TEST_FILL,
1446 : : TEST_M2D,
1447 : : TEST_ENQ_DEQ,
1448 : : TEST_END
1449 : : };
1450 : :
1451 : : static struct runtest_param param[] = {
1452 : : {"copy", test_enqueue_copies, 640},
1453 : : {"sg_copy", test_enqueue_sg_copies, 1},
1454 : : {"sva_copy", test_enqueue_sva_copies, 1},
1455 : : {"stop_start", test_stop_start, 1},
1456 : : {"burst_capacity", test_burst_capacity, 1},
1457 : : {"error_handling", test_completion_handling, 1},
1458 : : {"fill", test_enqueue_fill, 1},
1459 : : {"m2d_auto_free", test_m2d_auto_free, 128},
1460 : : {"dma_enq_deq", test_enq_deq_ops, 1},
1461 : : };
1462 : :
1463 : : static struct unit_test_suite ts = {
1464 : : .suite_name = "DMA dev instance testsuite",
1465 : : .setup = test_dmadev_setup,
1466 : : .teardown = test_dmadev_teardown,
1467 : : .unit_test_cases = {
1468 : : TEST_CASE_NAMED_WITH_DATA("copy",
1469 : : NULL, NULL,
1470 : : runtest, ¶m[TEST_COPY]),
1471 : : TEST_CASE_NAMED_WITH_DATA("sg_copy",
1472 : : test_dmadev_sg_copy_setup, NULL,
1473 : : runtest, ¶m[TEST_COPY_SG]),
1474 : : TEST_CASE_NAMED_WITH_DATA("sva_copy",
1475 : : test_dmadev_sva_setup, NULL,
1476 : : runtest, ¶m[TEST_SVA_COPY]),
1477 : : TEST_CASE_NAMED_WITH_DATA("stop_start",
1478 : : NULL, NULL,
1479 : : runtest, ¶m[TEST_START]),
1480 : : TEST_CASE_NAMED_WITH_DATA("burst_capacity",
1481 : : test_dmadev_burst_setup, NULL,
1482 : : runtest, ¶m[TEST_BURST]),
1483 : : TEST_CASE_NAMED_WITH_DATA("error_handling",
1484 : : test_dmadev_err_handling_setup, NULL,
1485 : : runtest, ¶m[TEST_ERR]),
1486 : : TEST_CASE_NAMED_WITH_DATA("fill",
1487 : : test_dmadev_fill_setup, NULL,
1488 : : runtest, ¶m[TEST_FILL]),
1489 : : TEST_CASE_NAMED_WITH_DATA("m2d_autofree",
1490 : : test_dmadev_autofree_setup, NULL,
1491 : : runtest, ¶m[TEST_M2D]),
1492 : : TEST_CASE_NAMED_WITH_DATA("dma_enq_deq",
1493 : : test_dmadev_enq_deq_setup, NULL,
1494 : : runtest, ¶m[TEST_ENQ_DEQ]),
1495 : : TEST_CASES_END()
1496 : : }
1497 : : };
1498 : :
1499 : : int ret;
1500 : :
1501 [ # # ]: 0 : if (rte_dma_info_get(dev_id, &dev_info) < 0)
1502 : : return TEST_SKIPPED;
1503 : :
1504 : 0 : test_dev_id = dev_id;
1505 : 0 : printf("\n### Test dmadev instance %u [%s]\n",
1506 : : test_dev_id, dev_info.dev_name);
1507 : :
1508 : 0 : ret = unit_test_suite_runner(&ts);
1509 : 0 : test_dev_id = -EINVAL;
1510 : :
1511 : 0 : return ret;
1512 : : }
1513 : :
1514 : : static void
1515 : 0 : parse_dma_env_var(void)
1516 : : {
1517 : 0 : char *dma_env_param_str = getenv("DPDK_ADD_DMA_TEST_PARAM");
1518 : 0 : char *dma_env_test_str = getenv("DPDK_ADD_DMA_TEST");
1519 : 0 : char *params[32] = {0};
1520 : 0 : char *tests[32] = {0};
1521 : 0 : char *var[2] = {0};
1522 : : int n_var = 0;
1523 : : int i, j;
1524 : :
1525 : : /* Additional test from commandline. */
1526 [ # # # # ]: 0 : if (dma_env_test_str && strlen(dma_env_test_str) > 0) {
1527 : 0 : n_var = rte_strsplit(dma_env_test_str, strlen(dma_env_test_str), tests,
1528 : : RTE_DIM(tests), ',');
1529 [ # # ]: 0 : for (i = 0; i < n_var; i++) {
1530 [ # # ]: 0 : for (j = 0; j < TEST_MAX; j++) {
1531 [ # # ]: 0 : if (!strcmp(tests[i], dma_add_test[j].name))
1532 : 0 : dma_add_test[j].enabled = true;
1533 : : }
1534 : : }
1535 : : }
1536 : :
1537 : : /* Commandline variables for test */
1538 [ # # # # ]: 0 : if (dma_env_param_str && strlen(dma_env_param_str) > 0) {
1539 : 0 : n_var = rte_strsplit(dma_env_param_str, strlen(dma_env_param_str), params,
1540 : : RTE_DIM(params), ',');
1541 [ # # ]: 0 : for (i = 0; i < n_var; i++) {
1542 : 0 : rte_strsplit(params[i], strlen(params[i]), var, RTE_DIM(var), '=');
1543 [ # # ]: 0 : for (j = 0; j < TEST_PARAM_MAX; j++) {
1544 [ # # ]: 0 : if (!strcmp(var[0], dma_test_param[j]))
1545 : 0 : env_test_param[j] = strtoul(var[1], NULL, 16);
1546 : : }
1547 : : }
1548 : : }
1549 : 0 : }
1550 : :
1551 : : static int
1552 : 0 : test_dma(void)
1553 : : {
1554 : : const char *pmd = "dma_skeleton";
1555 : : int i;
1556 : :
1557 : 0 : parse_dma_env_var();
1558 : :
1559 : : /* attempt to create skeleton instance - ignore errors due to one being already present*/
1560 : 0 : rte_vdev_init(pmd, NULL);
1561 : :
1562 [ # # ]: 0 : if (rte_dma_count_avail() == 0)
1563 : : return TEST_SKIPPED;
1564 : :
1565 [ # # ]: 0 : RTE_DMA_FOREACH_DEV(i) {
1566 [ # # ]: 0 : if (test_dma_api(i) < 0)
1567 : 0 : ERR_RETURN("Error performing API tests\n");
1568 : :
1569 [ # # ]: 0 : if (test_dmadev_instance(i) < 0)
1570 : 0 : ERR_RETURN("Error, test failure for device %d\n", i);
1571 : : }
1572 : :
1573 : : return 0;
1574 : : }
1575 : :
1576 : 254 : REGISTER_DRIVER_TEST(dmadev_autotest, test_dma);
|