1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2019 Intel Corporation
3  */
4 
5 #include <unistd.h>
6 #include <inttypes.h>
7 #include <rte_mbuf.h>
8 #include "rte_rawdev.h"
9 #include "rte_ioat_rawdev.h"
10 #include "ioat_private.h"
11 
12 #define MAX_SUPPORTED_RAWDEVS 64
13 #define TEST_SKIPPED 77
14 
15 int ioat_rawdev_test(uint16_t dev_id); /* pre-define to keep compiler happy */
16 
17 static struct rte_mempool *pool;
18 static unsigned short expected_ring_size[MAX_SUPPORTED_RAWDEVS];
19 
20 #define PRINT_ERR(...) print_err(__func__, __LINE__, __VA_ARGS__)
21 
22 static inline int
23 __rte_format_printf(3, 4)
print_err(const char * func,int lineno,const char * format,...)24 print_err(const char *func, int lineno, const char *format, ...)
25 {
26 	va_list ap;
27 	int ret;
28 
29 	ret = fprintf(stderr, "In %s:%d - ", func, lineno);
30 	va_start(ap, format);
31 	ret += vfprintf(stderr, format, ap);
32 	va_end(ap);
33 
34 	return ret;
35 }
36 
37 static int
test_enqueue_copies(int dev_id)38 test_enqueue_copies(int dev_id)
39 {
40 	const unsigned int length = 1024;
41 	unsigned int i;
42 
43 	do {
44 		struct rte_mbuf *src, *dst;
45 		char *src_data, *dst_data;
46 		struct rte_mbuf *completed[2] = {0};
47 
48 		/* test doing a single copy */
49 		src = rte_pktmbuf_alloc(pool);
50 		dst = rte_pktmbuf_alloc(pool);
51 		src->data_len = src->pkt_len = length;
52 		dst->data_len = dst->pkt_len = length;
53 		src_data = rte_pktmbuf_mtod(src, char *);
54 		dst_data = rte_pktmbuf_mtod(dst, char *);
55 
56 		for (i = 0; i < length; i++)
57 			src_data[i] = rand() & 0xFF;
58 
59 		if (rte_ioat_enqueue_copy(dev_id,
60 				src->buf_iova + src->data_off,
61 				dst->buf_iova + dst->data_off,
62 				length,
63 				(uintptr_t)src,
64 				(uintptr_t)dst) != 1) {
65 			PRINT_ERR("Error with rte_ioat_enqueue_copy\n");
66 			return -1;
67 		}
68 		rte_ioat_perform_ops(dev_id);
69 		usleep(10);
70 
71 		if (rte_ioat_completed_ops(dev_id, 1, (void *)&completed[0],
72 				(void *)&completed[1]) != 1) {
73 			PRINT_ERR("Error with rte_ioat_completed_ops\n");
74 			return -1;
75 		}
76 		if (completed[0] != src || completed[1] != dst) {
77 			PRINT_ERR("Error with completions: got (%p, %p), not (%p,%p)\n",
78 					completed[0], completed[1], src, dst);
79 			return -1;
80 		}
81 
82 		for (i = 0; i < length; i++)
83 			if (dst_data[i] != src_data[i]) {
84 				PRINT_ERR("Data mismatch at char %u\n", i);
85 				return -1;
86 			}
87 		rte_pktmbuf_free(src);
88 		rte_pktmbuf_free(dst);
89 	} while (0);
90 
91 	/* test doing multiple copies */
92 	do {
93 		struct rte_mbuf *srcs[32], *dsts[32];
94 		struct rte_mbuf *completed_src[64];
95 		struct rte_mbuf *completed_dst[64];
96 		unsigned int j;
97 
98 		for (i = 0; i < RTE_DIM(srcs); i++) {
99 			char *src_data;
100 
101 			srcs[i] = rte_pktmbuf_alloc(pool);
102 			dsts[i] = rte_pktmbuf_alloc(pool);
103 			srcs[i]->data_len = srcs[i]->pkt_len = length;
104 			dsts[i]->data_len = dsts[i]->pkt_len = length;
105 			src_data = rte_pktmbuf_mtod(srcs[i], char *);
106 
107 			for (j = 0; j < length; j++)
108 				src_data[j] = rand() & 0xFF;
109 
110 			if (rte_ioat_enqueue_copy(dev_id,
111 					srcs[i]->buf_iova + srcs[i]->data_off,
112 					dsts[i]->buf_iova + dsts[i]->data_off,
113 					length,
114 					(uintptr_t)srcs[i],
115 					(uintptr_t)dsts[i]) != 1) {
116 				PRINT_ERR("Error with rte_ioat_enqueue_copy for buffer %u\n",
117 						i);
118 				return -1;
119 			}
120 		}
121 		rte_ioat_perform_ops(dev_id);
122 		usleep(100);
123 
124 		if (rte_ioat_completed_ops(dev_id, 64, (void *)completed_src,
125 				(void *)completed_dst) != RTE_DIM(srcs)) {
126 			PRINT_ERR("Error with rte_ioat_completed_ops\n");
127 			return -1;
128 		}
129 		for (i = 0; i < RTE_DIM(srcs); i++) {
130 			char *src_data, *dst_data;
131 
132 			if (completed_src[i] != srcs[i]) {
133 				PRINT_ERR("Error with source pointer %u\n", i);
134 				return -1;
135 			}
136 			if (completed_dst[i] != dsts[i]) {
137 				PRINT_ERR("Error with dest pointer %u\n", i);
138 				return -1;
139 			}
140 
141 			src_data = rte_pktmbuf_mtod(srcs[i], char *);
142 			dst_data = rte_pktmbuf_mtod(dsts[i], char *);
143 			for (j = 0; j < length; j++)
144 				if (src_data[j] != dst_data[j]) {
145 					PRINT_ERR("Error with copy of packet %u, byte %u\n",
146 							i, j);
147 					return -1;
148 				}
149 			rte_pktmbuf_free(srcs[i]);
150 			rte_pktmbuf_free(dsts[i]);
151 		}
152 
153 	} while (0);
154 
155 	return 0;
156 }
157 
158 static int
test_enqueue_fill(int dev_id)159 test_enqueue_fill(int dev_id)
160 {
161 	const unsigned int length[] = {8, 64, 1024, 50, 100, 89};
162 	struct rte_mbuf *dst = rte_pktmbuf_alloc(pool);
163 	char *dst_data = rte_pktmbuf_mtod(dst, char *);
164 	struct rte_mbuf *completed[2] = {0};
165 	uint64_t pattern = 0xfedcba9876543210;
166 	unsigned int i, j;
167 
168 	for (i = 0; i < RTE_DIM(length); i++) {
169 		/* reset dst_data */
170 		memset(dst_data, 0, length[i]);
171 
172 		/* perform the fill operation */
173 		if (rte_ioat_enqueue_fill(dev_id, pattern,
174 				dst->buf_iova + dst->data_off, length[i],
175 				(uintptr_t)dst) != 1) {
176 			PRINT_ERR("Error with rte_ioat_enqueue_fill\n");
177 			return -1;
178 		}
179 
180 		rte_ioat_perform_ops(dev_id);
181 		usleep(100);
182 
183 		if (rte_ioat_completed_ops(dev_id, 1, (void *)&completed[0],
184 			(void *)&completed[1]) != 1) {
185 			PRINT_ERR("Error with completed ops\n");
186 			return -1;
187 		}
188 		/* check the result */
189 		for (j = 0; j < length[i]; j++) {
190 			char pat_byte = ((char *)&pattern)[j % 8];
191 			if (dst_data[j] != pat_byte) {
192 				PRINT_ERR("Error with fill operation (length = %u): got (%x), not (%x)\n",
193 						length[i], dst_data[j],
194 						pat_byte);
195 				return -1;
196 			}
197 		}
198 	}
199 
200 	rte_pktmbuf_free(dst);
201 	return 0;
202 }
203 
204 int
ioat_rawdev_test(uint16_t dev_id)205 ioat_rawdev_test(uint16_t dev_id)
206 {
207 #define IOAT_TEST_RINGSIZE 512
208 	struct rte_ioat_rawdev_config p = { .ring_size = -1 };
209 	struct rte_rawdev_info info = { .dev_private = &p };
210 	struct rte_rawdev_xstats_name *snames = NULL;
211 	uint64_t *stats = NULL;
212 	unsigned int *ids = NULL;
213 	unsigned int nb_xstats;
214 	unsigned int i;
215 
216 	if (dev_id >= MAX_SUPPORTED_RAWDEVS) {
217 		printf("Skipping test. Cannot test rawdevs with id's greater than %d\n",
218 				MAX_SUPPORTED_RAWDEVS);
219 		return TEST_SKIPPED;
220 	}
221 
222 	rte_rawdev_info_get(dev_id, &info, sizeof(p));
223 	if (p.ring_size != expected_ring_size[dev_id]) {
224 		PRINT_ERR("Error, initial ring size is not as expected (Actual: %d, Expected: %d)\n",
225 				(int)p.ring_size, expected_ring_size[dev_id]);
226 		return -1;
227 	}
228 
229 	p.ring_size = IOAT_TEST_RINGSIZE;
230 	if (rte_rawdev_configure(dev_id, &info, sizeof(p)) != 0) {
231 		PRINT_ERR("Error with rte_rawdev_configure()\n");
232 		return -1;
233 	}
234 	rte_rawdev_info_get(dev_id, &info, sizeof(p));
235 	if (p.ring_size != IOAT_TEST_RINGSIZE) {
236 		PRINT_ERR("Error, ring size is not %d (%d)\n",
237 				IOAT_TEST_RINGSIZE, (int)p.ring_size);
238 		return -1;
239 	}
240 	expected_ring_size[dev_id] = p.ring_size;
241 
242 	if (rte_rawdev_start(dev_id) != 0) {
243 		PRINT_ERR("Error with rte_rawdev_start()\n");
244 		return -1;
245 	}
246 
247 	pool = rte_pktmbuf_pool_create("TEST_IOAT_POOL",
248 			256, /* n == num elements */
249 			32,  /* cache size */
250 			0,   /* priv size */
251 			2048, /* data room size */
252 			info.socket_id);
253 	if (pool == NULL) {
254 		PRINT_ERR("Error with mempool creation\n");
255 		return -1;
256 	}
257 
258 	/* allocate memory for xstats names and values */
259 	nb_xstats = rte_rawdev_xstats_names_get(dev_id, NULL, 0);
260 
261 	snames = malloc(sizeof(*snames) * nb_xstats);
262 	if (snames == NULL) {
263 		PRINT_ERR("Error allocating xstat names memory\n");
264 		goto err;
265 	}
266 	rte_rawdev_xstats_names_get(dev_id, snames, nb_xstats);
267 
268 	ids = malloc(sizeof(*ids) * nb_xstats);
269 	if (ids == NULL) {
270 		PRINT_ERR("Error allocating xstat ids memory\n");
271 		goto err;
272 	}
273 	for (i = 0; i < nb_xstats; i++)
274 		ids[i] = i;
275 
276 	stats = malloc(sizeof(*stats) * nb_xstats);
277 	if (stats == NULL) {
278 		PRINT_ERR("Error allocating xstat memory\n");
279 		goto err;
280 	}
281 
282 	/* run the test cases */
283 	printf("Running Copy Tests\n");
284 	for (i = 0; i < 100; i++) {
285 		unsigned int j;
286 
287 		if (test_enqueue_copies(dev_id) != 0)
288 			goto err;
289 
290 		rte_rawdev_xstats_get(dev_id, ids, stats, nb_xstats);
291 		for (j = 0; j < nb_xstats; j++)
292 			printf("%s: %"PRIu64"   ", snames[j].name, stats[j]);
293 		printf("\r");
294 	}
295 	printf("\n");
296 
297 	/* test enqueue fill operation */
298 	printf("Running Fill Tests\n");
299 	for (i = 0; i < 100; i++) {
300 		unsigned int j;
301 
302 		if (test_enqueue_fill(dev_id) != 0)
303 			goto err;
304 
305 		rte_rawdev_xstats_get(dev_id, ids, stats, nb_xstats);
306 		for (j = 0; j < nb_xstats; j++)
307 			printf("%s: %"PRIu64"   ", snames[j].name, stats[j]);
308 		printf("\r");
309 	}
310 	printf("\n");
311 
312 	rte_rawdev_stop(dev_id);
313 	if (rte_rawdev_xstats_reset(dev_id, NULL, 0) != 0) {
314 		PRINT_ERR("Error resetting xstat values\n");
315 		goto err;
316 	}
317 
318 	rte_mempool_free(pool);
319 	free(snames);
320 	free(stats);
321 	free(ids);
322 	return 0;
323 
324 err:
325 	rte_rawdev_stop(dev_id);
326 	rte_rawdev_xstats_reset(dev_id, NULL, 0);
327 	rte_mempool_free(pool);
328 	free(snames);
329 	free(stats);
330 	free(ids);
331 	return -1;
332 }
333