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) 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 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 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 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