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