1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright 2017 NXP 3 */ 4 5 #include <assert.h> 6 #include <stdio.h> 7 #include <stdbool.h> 8 #include <errno.h> 9 #include <stdint.h> 10 #include <inttypes.h> 11 #include <string.h> 12 13 #include <rte_byteorder.h> 14 #include <rte_common.h> 15 #include <rte_debug.h> 16 #include <rte_dev.h> 17 #include <rte_eal.h> 18 #include <rte_kvargs.h> 19 #include <rte_log.h> 20 #include <rte_malloc.h> 21 #include <rte_memory.h> 22 #include <rte_memcpy.h> 23 #include <rte_lcore.h> 24 #include <rte_bus_vdev.h> 25 26 #include <rte_rawdev.h> 27 #include <rte_rawdev_pmd.h> 28 29 #include "skeleton_rawdev.h" 30 31 /* Count of instances */ 32 static uint16_t skeldev_init_once; 33 34 /**< Rawdev Skeleton dummy driver name */ 35 #define SKELETON_PMD_RAWDEV_NAME rawdev_skeleton 36 37 struct queue_buffers { 38 void *bufs[SKELETON_QUEUE_MAX_DEPTH]; 39 }; 40 41 static struct queue_buffers queue_buf[SKELETON_MAX_QUEUES] = {}; 42 static void clear_queue_bufs(int queue_id); 43 44 static void skeleton_rawdev_info_get(struct rte_rawdev *dev, 45 rte_rawdev_obj_t dev_info) 46 { 47 struct skeleton_rawdev *skeldev; 48 struct skeleton_rawdev_conf *skeldev_conf; 49 50 SKELETON_PMD_FUNC_TRACE(); 51 52 if (!dev_info) { 53 SKELETON_PMD_ERR("Invalid request"); 54 return; 55 } 56 57 skeldev = skeleton_rawdev_get_priv(dev); 58 59 skeldev_conf = dev_info; 60 61 skeldev_conf->num_queues = skeldev->num_queues; 62 skeldev_conf->capabilities = skeldev->capabilities; 63 skeldev_conf->device_state = skeldev->device_state; 64 skeldev_conf->firmware_state = skeldev->fw.firmware_state; 65 } 66 67 static int skeleton_rawdev_configure(const struct rte_rawdev *dev, 68 rte_rawdev_obj_t config) 69 { 70 struct skeleton_rawdev *skeldev; 71 struct skeleton_rawdev_conf *skeldev_conf; 72 73 SKELETON_PMD_FUNC_TRACE(); 74 75 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 76 77 if (!config) { 78 SKELETON_PMD_ERR("Invalid configuration"); 79 return -EINVAL; 80 } 81 82 skeldev_conf = config; 83 skeldev = skeleton_rawdev_get_priv(dev); 84 85 if (skeldev_conf->num_queues <= SKELETON_MAX_QUEUES) 86 skeldev->num_queues = skeldev_conf->num_queues; 87 else 88 return -EINVAL; 89 90 skeldev->capabilities = skeldev_conf->capabilities; 91 skeldev->num_queues = skeldev_conf->num_queues; 92 93 return 0; 94 } 95 96 static int skeleton_rawdev_start(struct rte_rawdev *dev) 97 { 98 int ret = 0; 99 struct skeleton_rawdev *skeldev; 100 enum skeleton_firmware_state fw_state; 101 enum skeleton_device_state device_state; 102 103 SKELETON_PMD_FUNC_TRACE(); 104 105 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 106 107 skeldev = skeleton_rawdev_get_priv(dev); 108 109 fw_state = skeldev->fw.firmware_state; 110 device_state = skeldev->device_state; 111 112 if (fw_state == SKELETON_FW_LOADED && 113 device_state == SKELETON_DEV_STOPPED) { 114 skeldev->device_state = SKELETON_DEV_RUNNING; 115 } else { 116 SKELETON_PMD_ERR("Device not ready for starting"); 117 ret = -EINVAL; 118 } 119 120 return ret; 121 } 122 123 static void skeleton_rawdev_stop(struct rte_rawdev *dev) 124 { 125 struct skeleton_rawdev *skeldev; 126 127 SKELETON_PMD_FUNC_TRACE(); 128 129 if (dev) { 130 skeldev = skeleton_rawdev_get_priv(dev); 131 skeldev->device_state = SKELETON_DEV_STOPPED; 132 } 133 } 134 135 static void 136 reset_queues(struct skeleton_rawdev *skeldev) 137 { 138 int i; 139 140 for (i = 0; i < SKELETON_MAX_QUEUES; i++) { 141 skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH; 142 skeldev->queues[i].state = SKELETON_QUEUE_DETACH; 143 } 144 } 145 146 static void 147 reset_attribute_table(struct skeleton_rawdev *skeldev) 148 { 149 int i; 150 151 for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { 152 if (skeldev->attr[i].name) { 153 free(skeldev->attr[i].name); 154 skeldev->attr[i].name = NULL; 155 } 156 } 157 } 158 159 static int skeleton_rawdev_close(struct rte_rawdev *dev) 160 { 161 int ret = 0, i; 162 struct skeleton_rawdev *skeldev; 163 enum skeleton_firmware_state fw_state; 164 enum skeleton_device_state device_state; 165 166 SKELETON_PMD_FUNC_TRACE(); 167 168 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 169 170 skeldev = skeleton_rawdev_get_priv(dev); 171 172 fw_state = skeldev->fw.firmware_state; 173 device_state = skeldev->device_state; 174 175 reset_queues(skeldev); 176 reset_attribute_table(skeldev); 177 178 switch (fw_state) { 179 case SKELETON_FW_LOADED: 180 if (device_state == SKELETON_DEV_RUNNING) { 181 SKELETON_PMD_ERR("Cannot close running device"); 182 ret = -EINVAL; 183 } else { 184 /* Probably call fw reset here */ 185 skeldev->fw.firmware_state = SKELETON_FW_READY; 186 } 187 break; 188 case SKELETON_FW_READY: 189 case SKELETON_FW_ERROR: 190 default: 191 SKELETON_PMD_DEBUG("Device already in stopped state"); 192 ret = -EINVAL; 193 break; 194 } 195 196 /* Clear all allocated queues */ 197 for (i = 0; i < SKELETON_MAX_QUEUES; i++) 198 clear_queue_bufs(i); 199 200 return ret; 201 } 202 203 static int skeleton_rawdev_reset(struct rte_rawdev *dev) 204 { 205 struct skeleton_rawdev *skeldev; 206 207 SKELETON_PMD_FUNC_TRACE(); 208 209 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 210 211 skeldev = skeleton_rawdev_get_priv(dev); 212 213 SKELETON_PMD_DEBUG("Resetting device"); 214 skeldev->fw.firmware_state = SKELETON_FW_READY; 215 216 return 0; 217 } 218 219 static void skeleton_rawdev_queue_def_conf(struct rte_rawdev *dev, 220 uint16_t queue_id, 221 rte_rawdev_obj_t queue_conf) 222 { 223 struct skeleton_rawdev *skeldev; 224 struct skeleton_rawdev_queue *skelq; 225 226 SKELETON_PMD_FUNC_TRACE(); 227 228 if (!dev || !queue_conf) 229 return; 230 231 skeldev = skeleton_rawdev_get_priv(dev); 232 skelq = &skeldev->queues[queue_id]; 233 234 if (queue_id < SKELETON_MAX_QUEUES) 235 rte_memcpy(queue_conf, skelq, 236 sizeof(struct skeleton_rawdev_queue)); 237 } 238 239 static void 240 clear_queue_bufs(int queue_id) 241 { 242 int i; 243 244 /* Clear buffers for queue_id */ 245 for (i = 0; i < SKELETON_QUEUE_MAX_DEPTH; i++) 246 queue_buf[queue_id].bufs[i] = NULL; 247 } 248 249 static int skeleton_rawdev_queue_setup(struct rte_rawdev *dev, 250 uint16_t queue_id, 251 rte_rawdev_obj_t queue_conf) 252 { 253 int ret = 0; 254 struct skeleton_rawdev *skeldev; 255 struct skeleton_rawdev_queue *q; 256 257 SKELETON_PMD_FUNC_TRACE(); 258 259 if (!dev || !queue_conf) 260 return -EINVAL; 261 262 skeldev = skeleton_rawdev_get_priv(dev); 263 q = &skeldev->queues[queue_id]; 264 265 if (skeldev->num_queues > queue_id && 266 q->depth < SKELETON_QUEUE_MAX_DEPTH) { 267 rte_memcpy(q, queue_conf, 268 sizeof(struct skeleton_rawdev_queue)); 269 clear_queue_bufs(queue_id); 270 } else { 271 SKELETON_PMD_ERR("Invalid queue configuration"); 272 ret = -EINVAL; 273 } 274 275 return ret; 276 } 277 278 static int skeleton_rawdev_queue_release(struct rte_rawdev *dev, 279 uint16_t queue_id) 280 { 281 int ret = 0; 282 struct skeleton_rawdev *skeldev; 283 284 SKELETON_PMD_FUNC_TRACE(); 285 286 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 287 288 skeldev = skeleton_rawdev_get_priv(dev); 289 290 if (skeldev->num_queues > queue_id) { 291 skeldev->queues[queue_id].state = SKELETON_QUEUE_DETACH; 292 skeldev->queues[queue_id].depth = SKELETON_QUEUE_DEF_DEPTH; 293 clear_queue_bufs(queue_id); 294 } else { 295 SKELETON_PMD_ERR("Invalid queue configuration"); 296 ret = -EINVAL; 297 } 298 299 return ret; 300 } 301 302 static uint16_t skeleton_rawdev_queue_count(struct rte_rawdev *dev) 303 { 304 struct skeleton_rawdev *skeldev; 305 306 SKELETON_PMD_FUNC_TRACE(); 307 308 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 309 310 skeldev = skeleton_rawdev_get_priv(dev); 311 return skeldev->num_queues; 312 } 313 314 static int skeleton_rawdev_get_attr(struct rte_rawdev *dev, 315 const char *attr_name, 316 uint64_t *attr_value) 317 { 318 int i; 319 uint8_t done = 0; 320 struct skeleton_rawdev *skeldev; 321 322 SKELETON_PMD_FUNC_TRACE(); 323 324 if (!dev || !attr_name || !attr_value) { 325 SKELETON_PMD_ERR("Invalid arguments for getting attributes"); 326 return -EINVAL; 327 } 328 329 skeldev = skeleton_rawdev_get_priv(dev); 330 331 for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { 332 if (!skeldev->attr[i].name) 333 continue; 334 335 if (!strncmp(skeldev->attr[i].name, attr_name, 336 SKELETON_ATTRIBUTE_NAME_MAX)) { 337 *attr_value = skeldev->attr[i].value; 338 done = 1; 339 SKELETON_PMD_DEBUG("Attribute (%s) Value (%" PRIu64 ")", 340 attr_name, *attr_value); 341 break; 342 } 343 } 344 345 if (done) 346 return 0; 347 348 /* Attribute not found */ 349 return -EINVAL; 350 } 351 352 static int skeleton_rawdev_set_attr(struct rte_rawdev *dev, 353 const char *attr_name, 354 const uint64_t attr_value) 355 { 356 int i; 357 uint8_t done = 0; 358 struct skeleton_rawdev *skeldev; 359 360 SKELETON_PMD_FUNC_TRACE(); 361 362 if (!dev || !attr_name) { 363 SKELETON_PMD_ERR("Invalid arguments for setting attributes"); 364 return -EINVAL; 365 } 366 367 skeldev = skeleton_rawdev_get_priv(dev); 368 369 /* Check if attribute already exists */ 370 for (i = 0; i < SKELETON_MAX_ATTRIBUTES; i++) { 371 if (!skeldev->attr[i].name) 372 break; 373 374 if (!strncmp(skeldev->attr[i].name, attr_name, 375 SKELETON_ATTRIBUTE_NAME_MAX)) { 376 /* Update value */ 377 skeldev->attr[i].value = attr_value; 378 done = 1; 379 break; 380 } 381 } 382 383 if (!done) { 384 if (i < (SKELETON_MAX_ATTRIBUTES - 1)) { 385 /* There is still space to insert one more */ 386 skeldev->attr[i].name = strdup(attr_name); 387 if (!skeldev->attr[i].name) 388 return -ENOMEM; 389 390 skeldev->attr[i].value = attr_value; 391 return 0; 392 } 393 } 394 395 return -EINVAL; 396 } 397 398 static int skeleton_rawdev_enqueue_bufs(struct rte_rawdev *dev, 399 struct rte_rawdev_buf **buffers, 400 unsigned int count, 401 rte_rawdev_obj_t context) 402 { 403 unsigned int i; 404 uint16_t q_id; 405 RTE_SET_USED(dev); 406 407 /* context is essentially the queue_id which is 408 * transferred as opaque object through the library layer. This can 409 * help in complex implementation which require more information than 410 * just an integer - for example, a queue-pair. 411 */ 412 q_id = *((int *)context); 413 414 for (i = 0; i < count; i++) 415 queue_buf[q_id].bufs[i] = buffers[i]->buf_addr; 416 417 return i; 418 } 419 420 static int skeleton_rawdev_dequeue_bufs(struct rte_rawdev *dev, 421 struct rte_rawdev_buf **buffers, 422 unsigned int count, 423 rte_rawdev_obj_t context) 424 { 425 unsigned int i; 426 uint16_t q_id; 427 RTE_SET_USED(dev); 428 429 /* context is essentially the queue_id which is 430 * transferred as opaque object through the library layer. This can 431 * help in complex implementation which require more information than 432 * just an integer - for example, a queue-pair. 433 */ 434 q_id = *((int *)context); 435 436 for (i = 0; i < count; i++) 437 buffers[i]->buf_addr = queue_buf[q_id].bufs[i]; 438 439 return i; 440 } 441 442 static int skeleton_rawdev_dump(struct rte_rawdev *dev, FILE *f) 443 { 444 RTE_SET_USED(dev); 445 RTE_SET_USED(f); 446 447 return 0; 448 } 449 450 static int skeleton_rawdev_firmware_status_get(struct rte_rawdev *dev, 451 rte_rawdev_obj_t status_info) 452 { 453 struct skeleton_rawdev *skeldev; 454 455 SKELETON_PMD_FUNC_TRACE(); 456 457 skeldev = skeleton_rawdev_get_priv(dev); 458 459 RTE_FUNC_PTR_OR_ERR_RET(dev, -EINVAL); 460 461 if (status_info) 462 memcpy(status_info, &skeldev->fw.firmware_state, 463 sizeof(enum skeleton_firmware_state)); 464 465 return 0; 466 } 467 468 469 static int skeleton_rawdev_firmware_version_get( 470 struct rte_rawdev *dev, 471 rte_rawdev_obj_t version_info) 472 { 473 struct skeleton_rawdev *skeldev; 474 struct skeleton_firmware_version_info *vi; 475 476 SKELETON_PMD_FUNC_TRACE(); 477 478 skeldev = skeleton_rawdev_get_priv(dev); 479 vi = version_info; 480 481 vi->major = skeldev->fw.firmware_version.major; 482 vi->minor = skeldev->fw.firmware_version.minor; 483 vi->subrel = skeldev->fw.firmware_version.subrel; 484 485 return 0; 486 } 487 488 static int skeleton_rawdev_firmware_load(struct rte_rawdev *dev, 489 rte_rawdev_obj_t firmware_buf) 490 { 491 struct skeleton_rawdev *skeldev; 492 493 SKELETON_PMD_FUNC_TRACE(); 494 495 skeldev = skeleton_rawdev_get_priv(dev); 496 497 /* firmware_buf is a mmaped, possibly DMA'able area, buffer. Being 498 * dummy, all this does is check if firmware_buf is not NULL and 499 * sets the state of the firmware. 500 */ 501 if (!firmware_buf) 502 return -EINVAL; 503 504 skeldev->fw.firmware_state = SKELETON_FW_LOADED; 505 506 return 0; 507 } 508 509 static int skeleton_rawdev_firmware_unload(struct rte_rawdev *dev) 510 { 511 struct skeleton_rawdev *skeldev; 512 513 SKELETON_PMD_FUNC_TRACE(); 514 515 skeldev = skeleton_rawdev_get_priv(dev); 516 517 skeldev->fw.firmware_state = SKELETON_FW_READY; 518 519 return 0; 520 } 521 522 static const struct rte_rawdev_ops skeleton_rawdev_ops = { 523 .dev_info_get = skeleton_rawdev_info_get, 524 .dev_configure = skeleton_rawdev_configure, 525 .dev_start = skeleton_rawdev_start, 526 .dev_stop = skeleton_rawdev_stop, 527 .dev_close = skeleton_rawdev_close, 528 .dev_reset = skeleton_rawdev_reset, 529 530 .queue_def_conf = skeleton_rawdev_queue_def_conf, 531 .queue_setup = skeleton_rawdev_queue_setup, 532 .queue_release = skeleton_rawdev_queue_release, 533 .queue_count = skeleton_rawdev_queue_count, 534 535 .attr_get = skeleton_rawdev_get_attr, 536 .attr_set = skeleton_rawdev_set_attr, 537 538 .enqueue_bufs = skeleton_rawdev_enqueue_bufs, 539 .dequeue_bufs = skeleton_rawdev_dequeue_bufs, 540 541 .dump = skeleton_rawdev_dump, 542 543 .xstats_get = NULL, 544 .xstats_get_names = NULL, 545 .xstats_get_by_name = NULL, 546 .xstats_reset = NULL, 547 548 .firmware_status_get = skeleton_rawdev_firmware_status_get, 549 .firmware_version_get = skeleton_rawdev_firmware_version_get, 550 .firmware_load = skeleton_rawdev_firmware_load, 551 .firmware_unload = skeleton_rawdev_firmware_unload, 552 553 .dev_selftest = test_rawdev_skeldev, 554 }; 555 556 static int 557 skeleton_rawdev_create(const char *name, 558 struct rte_vdev_device *vdev, 559 int socket_id) 560 { 561 int ret = 0, i; 562 struct rte_rawdev *rawdev = NULL; 563 struct skeleton_rawdev *skeldev = NULL; 564 565 if (!name) { 566 SKELETON_PMD_ERR("Invalid name of the device!"); 567 ret = -EINVAL; 568 goto cleanup; 569 } 570 571 /* Allocate device structure */ 572 rawdev = rte_rawdev_pmd_allocate(name, sizeof(struct skeleton_rawdev), 573 socket_id); 574 if (rawdev == NULL) { 575 SKELETON_PMD_ERR("Unable to allocate rawdevice"); 576 ret = -EINVAL; 577 goto cleanup; 578 } 579 580 ret = rawdev->dev_id; /* return the rawdev id of new device */ 581 582 rawdev->dev_ops = &skeleton_rawdev_ops; 583 rawdev->device = &vdev->device; 584 585 skeldev = skeleton_rawdev_get_priv(rawdev); 586 587 skeldev->device_id = SKELETON_DEVICE_ID; 588 skeldev->vendor_id = SKELETON_VENDOR_ID; 589 skeldev->capabilities = SKELETON_DEFAULT_CAPA; 590 591 memset(&skeldev->fw, 0, sizeof(struct skeleton_firmware)); 592 593 skeldev->fw.firmware_state = SKELETON_FW_READY; 594 skeldev->fw.firmware_version.major = SKELETON_MAJOR_VER; 595 skeldev->fw.firmware_version.minor = SKELETON_MINOR_VER; 596 skeldev->fw.firmware_version.subrel = SKELETON_SUB_VER; 597 598 skeldev->device_state = SKELETON_DEV_STOPPED; 599 600 /* Reset/set to default queue configuration for this device */ 601 for (i = 0; i < SKELETON_MAX_QUEUES; i++) { 602 skeldev->queues[i].state = SKELETON_QUEUE_DETACH; 603 skeldev->queues[i].depth = SKELETON_QUEUE_DEF_DEPTH; 604 } 605 606 /* Clear all allocated queue buffers */ 607 for (i = 0; i < SKELETON_MAX_QUEUES; i++) 608 clear_queue_bufs(i); 609 610 return ret; 611 612 cleanup: 613 if (rawdev) 614 rte_rawdev_pmd_release(rawdev); 615 616 return ret; 617 } 618 619 static int 620 skeleton_rawdev_destroy(const char *name) 621 { 622 int ret; 623 struct rte_rawdev *rdev; 624 625 if (!name) { 626 SKELETON_PMD_ERR("Invalid device name"); 627 return -EINVAL; 628 } 629 630 rdev = rte_rawdev_pmd_get_named_dev(name); 631 if (!rdev) { 632 SKELETON_PMD_ERR("Invalid device name (%s)", name); 633 return -EINVAL; 634 } 635 636 /* rte_rawdev_close is called by pmd_release */ 637 ret = rte_rawdev_pmd_release(rdev); 638 if (ret) 639 SKELETON_PMD_DEBUG("Device cleanup failed"); 640 641 return 0; 642 } 643 644 static int 645 skeldev_get_selftest(const char *key __rte_unused, 646 const char *value, 647 void *opaque) 648 { 649 int *flag = opaque; 650 *flag = atoi(value); 651 return 0; 652 } 653 654 static int 655 skeldev_parse_vdev_args(struct rte_vdev_device *vdev) 656 { 657 int selftest = 0; 658 const char *name; 659 const char *params; 660 661 static const char *const args[] = { 662 SKELETON_SELFTEST_ARG, 663 NULL 664 }; 665 666 name = rte_vdev_device_name(vdev); 667 668 params = rte_vdev_device_args(vdev); 669 if (params != NULL && params[0] != '\0') { 670 struct rte_kvargs *kvlist = rte_kvargs_parse(params, args); 671 672 if (!kvlist) { 673 SKELETON_PMD_INFO( 674 "Ignoring unsupported params supplied '%s'", 675 name); 676 } else { 677 int ret = rte_kvargs_process(kvlist, 678 SKELETON_SELFTEST_ARG, 679 skeldev_get_selftest, &selftest); 680 if (ret != 0 || (selftest < 0 || selftest > 1)) { 681 SKELETON_PMD_ERR("%s: Error in parsing args", 682 name); 683 rte_kvargs_free(kvlist); 684 ret = -1; /* enforce if selftest is invalid */ 685 return ret; 686 } 687 } 688 689 rte_kvargs_free(kvlist); 690 } 691 692 return selftest; 693 } 694 695 static int 696 skeleton_rawdev_probe(struct rte_vdev_device *vdev) 697 { 698 const char *name; 699 int selftest = 0, ret = 0; 700 701 702 name = rte_vdev_device_name(vdev); 703 if (name == NULL) 704 return -EINVAL; 705 706 /* More than one instance is not supported */ 707 if (skeldev_init_once) { 708 SKELETON_PMD_ERR("Multiple instance not supported for %s", 709 name); 710 return -EINVAL; 711 } 712 713 SKELETON_PMD_INFO("Init %s on NUMA node %d", name, rte_socket_id()); 714 715 selftest = skeldev_parse_vdev_args(vdev); 716 /* In case of invalid argument, selftest != 1; ignore other values */ 717 718 ret = skeleton_rawdev_create(name, vdev, rte_socket_id()); 719 if (ret >= 0) { 720 /* In case command line argument for 'selftest' was passed; 721 * if invalid arguments were passed, execution continues but 722 * without selftest. 723 */ 724 if (selftest == 1) 725 test_rawdev_skeldev(ret); 726 } 727 728 /* Device instance created; Second instance not possible */ 729 skeldev_init_once = 1; 730 731 return ret < 0 ? ret : 0; 732 } 733 734 static int 735 skeleton_rawdev_remove(struct rte_vdev_device *vdev) 736 { 737 const char *name; 738 int ret; 739 740 name = rte_vdev_device_name(vdev); 741 if (name == NULL) 742 return -1; 743 744 SKELETON_PMD_INFO("Closing %s on NUMA node %d", name, rte_socket_id()); 745 746 ret = skeleton_rawdev_destroy(name); 747 if (!ret) 748 skeldev_init_once = 0; 749 750 return ret; 751 } 752 753 static struct rte_vdev_driver skeleton_pmd_drv = { 754 .probe = skeleton_rawdev_probe, 755 .remove = skeleton_rawdev_remove 756 }; 757 758 RTE_PMD_REGISTER_VDEV(SKELETON_PMD_RAWDEV_NAME, skeleton_pmd_drv); 759 RTE_LOG_REGISTER(skeleton_pmd_logtype, rawdev.skeleton, INFO); 760