test/dma: run test suite on skeleton driver
[dpdk.git] / app / test / test_dmadev.c
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 COPY_LEN 1024
22
23 static struct rte_mempool *pool;
24 static uint16_t id_count;
25
26 static void
27 __rte_format_printf(3, 4)
28 print_err(const char *func, int lineno, const char *format, ...)
29 {
30         va_list ap;
31
32         fprintf(stderr, "In %s:%d - ", func, lineno);
33         va_start(ap, format);
34         vfprintf(stderr, format, ap);
35         va_end(ap);
36 }
37
38 static int
39 runtest(const char *printable, int (*test_fn)(int16_t dev_id, uint16_t vchan), int iterations,
40                 int16_t dev_id, uint16_t vchan, bool check_err_stats)
41 {
42         struct rte_dma_stats stats;
43         int i;
44
45         rte_dma_stats_reset(dev_id, vchan);
46         printf("DMA Dev %d: Running %s Tests %s\n", dev_id, printable,
47                         check_err_stats ? " " : "(errors expected)");
48         for (i = 0; i < iterations; i++) {
49                 if (test_fn(dev_id, vchan) < 0)
50                         return -1;
51
52                 rte_dma_stats_get(dev_id, 0, &stats);
53                 printf("Ops submitted: %"PRIu64"\t", stats.submitted);
54                 printf("Ops completed: %"PRIu64"\t", stats.completed);
55                 printf("Errors: %"PRIu64"\r", stats.errors);
56
57                 if (stats.completed != stats.submitted)
58                         ERR_RETURN("\nError, not all submitted jobs are reported as completed\n");
59                 if (check_err_stats && stats.errors != 0)
60                         ERR_RETURN("\nErrors reported during op processing, aborting tests\n");
61         }
62         printf("\n");
63         return 0;
64 }
65
66 static void
67 await_hw(int16_t dev_id, uint16_t vchan)
68 {
69         enum rte_dma_vchan_status st;
70
71         if (rte_dma_vchan_status(dev_id, vchan, &st) < 0) {
72                 /* for drivers that don't support this op, just sleep for 1 millisecond */
73                 rte_delay_us_sleep(1000);
74                 return;
75         }
76
77         /* for those that do, *max* end time is one second from now, but all should be faster */
78         const uint64_t end_cycles = rte_get_timer_cycles() + rte_get_timer_hz();
79         while (st == RTE_DMA_VCHAN_ACTIVE && rte_get_timer_cycles() < end_cycles) {
80                 rte_pause();
81                 rte_dma_vchan_status(dev_id, vchan, &st);
82         }
83 }
84
85 static int
86 test_enqueue_copies(int16_t dev_id, uint16_t vchan)
87 {
88         unsigned int i;
89         uint16_t id;
90
91         /* test doing a single copy */
92         do {
93                 struct rte_mbuf *src, *dst;
94                 char *src_data, *dst_data;
95
96                 src = rte_pktmbuf_alloc(pool);
97                 dst = rte_pktmbuf_alloc(pool);
98                 src_data = rte_pktmbuf_mtod(src, char *);
99                 dst_data = rte_pktmbuf_mtod(dst, char *);
100
101                 for (i = 0; i < COPY_LEN; i++)
102                         src_data[i] = rte_rand() & 0xFF;
103
104                 id = rte_dma_copy(dev_id, vchan, rte_pktmbuf_iova(src), rte_pktmbuf_iova(dst),
105                                 COPY_LEN, RTE_DMA_OP_FLAG_SUBMIT);
106                 if (id != id_count)
107                         ERR_RETURN("Error with rte_dma_copy, got %u, expected %u\n",
108                                         id, id_count);
109
110                 /* give time for copy to finish, then check it was done */
111                 await_hw(dev_id, vchan);
112
113                 for (i = 0; i < COPY_LEN; i++)
114                         if (dst_data[i] != src_data[i])
115                                 ERR_RETURN("Data mismatch at char %u [Got %02x not %02x]\n", i,
116                                                 dst_data[i], src_data[i]);
117
118                 /* now check completion works */
119                 if (rte_dma_completed(dev_id, vchan, 1, &id, NULL) != 1)
120                         ERR_RETURN("Error with rte_dma_completed\n");
121
122                 if (id != id_count)
123                         ERR_RETURN("Error:incorrect job id received, %u [expected %u]\n",
124                                         id, id_count);
125
126                 rte_pktmbuf_free(src);
127                 rte_pktmbuf_free(dst);
128
129                 /* now check completion returns nothing more */
130                 if (rte_dma_completed(dev_id, 0, 1, NULL, NULL) != 0)
131                         ERR_RETURN("Error with rte_dma_completed in empty check\n");
132
133                 id_count++;
134
135         } while (0);
136
137         /* test doing a multiple single copies */
138         do {
139                 const uint16_t max_ops = 4;
140                 struct rte_mbuf *src, *dst;
141                 char *src_data, *dst_data;
142                 uint16_t count;
143
144                 src = rte_pktmbuf_alloc(pool);
145                 dst = rte_pktmbuf_alloc(pool);
146                 src_data = rte_pktmbuf_mtod(src, char *);
147                 dst_data = rte_pktmbuf_mtod(dst, char *);
148
149                 for (i = 0; i < COPY_LEN; i++)
150                         src_data[i] = rte_rand() & 0xFF;
151
152                 /* perform the same copy <max_ops> times */
153                 for (i = 0; i < max_ops; i++)
154                         if (rte_dma_copy(dev_id, vchan,
155                                         rte_pktmbuf_iova(src),
156                                         rte_pktmbuf_iova(dst),
157                                         COPY_LEN, RTE_DMA_OP_FLAG_SUBMIT) != id_count++)
158                                 ERR_RETURN("Error with rte_dma_copy\n");
159
160                 await_hw(dev_id, vchan);
161
162                 count = rte_dma_completed(dev_id, vchan, max_ops * 2, &id, NULL);
163                 if (count != max_ops)
164                         ERR_RETURN("Error with rte_dma_completed, got %u not %u\n",
165                                         count, max_ops);
166
167                 if (id != id_count - 1)
168                         ERR_RETURN("Error, incorrect job id returned: got %u not %u\n",
169                                         id, id_count - 1);
170
171                 for (i = 0; i < COPY_LEN; i++)
172                         if (dst_data[i] != src_data[i])
173                                 ERR_RETURN("Data mismatch at char %u\n", i);
174
175                 rte_pktmbuf_free(src);
176                 rte_pktmbuf_free(dst);
177         } while (0);
178
179         return 0;
180 }
181
182 static int
183 test_dmadev_instance(int16_t dev_id)
184 {
185 #define TEST_RINGSIZE 512
186 #define CHECK_ERRS    true
187         struct rte_dma_stats stats;
188         struct rte_dma_info info;
189         const struct rte_dma_conf conf = { .nb_vchans = 1};
190         const struct rte_dma_vchan_conf qconf = {
191                         .direction = RTE_DMA_DIR_MEM_TO_MEM,
192                         .nb_desc = TEST_RINGSIZE,
193         };
194         const int vchan = 0;
195
196         printf("\n### Test dmadev instance %u [%s]\n",
197                         dev_id, rte_dma_devices[dev_id].data->dev_name);
198
199         rte_dma_info_get(dev_id, &info);
200         if (info.max_vchans < 1)
201                 ERR_RETURN("Error, no channels available on device id %u\n", dev_id);
202
203         if (rte_dma_configure(dev_id, &conf) != 0)
204                 ERR_RETURN("Error with rte_dma_configure()\n");
205
206         if (rte_dma_vchan_setup(dev_id, vchan, &qconf) < 0)
207                 ERR_RETURN("Error with queue configuration\n");
208
209         rte_dma_info_get(dev_id, &info);
210         if (info.nb_vchans != 1)
211                 ERR_RETURN("Error, no configured queues reported on device id %u\n", dev_id);
212
213         if (rte_dma_start(dev_id) != 0)
214                 ERR_RETURN("Error with rte_dma_start()\n");
215
216         if (rte_dma_stats_get(dev_id, vchan, &stats) != 0)
217                 ERR_RETURN("Error with rte_dma_stats_get()\n");
218
219         if (stats.completed != 0 || stats.submitted != 0 || stats.errors != 0)
220                 ERR_RETURN("Error device stats are not all zero: completed = %"PRIu64", "
221                                 "submitted = %"PRIu64", errors = %"PRIu64"\n",
222                                 stats.completed, stats.submitted, stats.errors);
223         id_count = 0;
224
225         /* create a mempool for running tests */
226         pool = rte_pktmbuf_pool_create("TEST_DMADEV_POOL",
227                         TEST_RINGSIZE * 2, /* n == num elements */
228                         32,  /* cache size */
229                         0,   /* priv size */
230                         2048, /* data room size */
231                         info.numa_node);
232         if (pool == NULL)
233                 ERR_RETURN("Error with mempool creation\n");
234
235         /* run the test cases, use many iterations to ensure UINT16_MAX id wraparound */
236         if (runtest("copy", test_enqueue_copies, 640, dev_id, vchan, CHECK_ERRS) < 0)
237                 goto err;
238
239         rte_mempool_free(pool);
240         rte_dma_stop(dev_id);
241         rte_dma_stats_reset(dev_id, vchan);
242         return 0;
243
244 err:
245         rte_mempool_free(pool);
246         rte_dma_stop(dev_id);
247         return -1;
248 }
249
250 static int
251 test_apis(void)
252 {
253         const char *pmd = "dma_skeleton";
254         int id;
255         int ret;
256
257         /* attempt to create skeleton instance - ignore errors due to one being already present */
258         rte_vdev_init(pmd, NULL);
259         id = rte_dma_get_dev_id_by_name(pmd);
260         if (id < 0)
261                 return TEST_SKIPPED;
262         printf("\n### Test dmadev infrastructure using skeleton driver\n");
263         ret = test_dma_api(id);
264
265         return ret;
266 }
267
268 static int
269 test_dma(void)
270 {
271         int i;
272
273         /* basic sanity on dmadev infrastructure */
274         if (test_apis() < 0)
275                 ERR_RETURN("Error performing API tests\n");
276
277         if (rte_dma_count_avail() == 0)
278                 return TEST_SKIPPED;
279
280         RTE_DMA_FOREACH_DEV(i)
281                 if (test_dmadev_instance(i) < 0)
282                         ERR_RETURN("Error, test failure for device %d\n", i);
283
284         return 0;
285 }
286
287 REGISTER_TEST_COMMAND(dmadev_autotest, test_dma);