1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation. 3 * Copyright(c) 2014 6WIND S.A. 4 */ 5 6 #include <stdio.h> 7 #include <stdlib.h> 8 #include <string.h> 9 #include <sys/queue.h> 10 11 #include <bus_driver.h> 12 #include <rte_class.h> 13 #include <dev_driver.h> 14 #include <rte_devargs.h> 15 #include <rte_errno.h> 16 #include <rte_log.h> 17 #include <rte_spinlock.h> 18 #include <rte_string_fns.h> 19 20 #include "eal_private.h" 21 #include "hotplug_mp.h" 22 23 const char * 24 rte_driver_name(const struct rte_driver *driver) 25 { 26 return driver->name; 27 } 28 29 const struct rte_bus * 30 rte_dev_bus(const struct rte_device *dev) 31 { 32 return dev->bus; 33 } 34 35 const struct rte_devargs * 36 rte_dev_devargs(const struct rte_device *dev) 37 { 38 return dev->devargs; 39 } 40 41 const struct rte_driver * 42 rte_dev_driver(const struct rte_device *dev) 43 { 44 return dev->driver; 45 } 46 47 const char * 48 rte_dev_name(const struct rte_device *dev) 49 { 50 return dev->name; 51 } 52 53 int 54 rte_dev_numa_node(const struct rte_device *dev) 55 { 56 return dev->numa_node; 57 } 58 59 /** 60 * The device event callback description. 61 * 62 * It contains callback address to be registered by user application, 63 * the pointer to the parameters for callback, and the device name. 64 */ 65 struct dev_event_callback { 66 TAILQ_ENTRY(dev_event_callback) next; /**< Callbacks list */ 67 rte_dev_event_cb_fn cb_fn; /**< Callback address */ 68 void *cb_arg; /**< Callback parameter */ 69 char *dev_name; /**< Callback device name, NULL is for all device */ 70 uint32_t active; /**< Callback is executing */ 71 }; 72 73 /** @internal Structure to keep track of registered callbacks */ 74 TAILQ_HEAD(dev_event_cb_list, dev_event_callback); 75 76 /* The device event callback list for all registered callbacks. */ 77 static struct dev_event_cb_list dev_event_cbs; 78 79 /* spinlock for device callbacks */ 80 static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER; 81 82 struct dev_next_ctx { 83 struct rte_dev_iterator *it; 84 const char *bus_str; 85 const char *cls_str; 86 }; 87 88 #define CTX(it, bus_str, cls_str) \ 89 (&(const struct dev_next_ctx){ \ 90 .it = it, \ 91 .bus_str = bus_str, \ 92 .cls_str = cls_str, \ 93 }) 94 95 #define ITCTX(ptr) \ 96 (((struct dev_next_ctx *)(intptr_t)ptr)->it) 97 98 #define BUSCTX(ptr) \ 99 (((struct dev_next_ctx *)(intptr_t)ptr)->bus_str) 100 101 #define CLSCTX(ptr) \ 102 (((struct dev_next_ctx *)(intptr_t)ptr)->cls_str) 103 104 static int cmp_dev_name(const struct rte_device *dev, const void *_name) 105 { 106 const char *name = _name; 107 108 return strcmp(dev->name, name); 109 } 110 111 int 112 rte_dev_is_probed(const struct rte_device *dev) 113 { 114 /* The field driver should be set only when the probe is successful. */ 115 return dev->driver != NULL; 116 } 117 118 /* helper function to build devargs, caller should free the memory */ 119 static int 120 build_devargs(const char *busname, const char *devname, 121 const char *drvargs, char **devargs) 122 { 123 int length; 124 125 length = snprintf(NULL, 0, "%s:%s,%s", busname, devname, drvargs); 126 if (length < 0) 127 return -EINVAL; 128 129 *devargs = malloc(length + 1); 130 if (*devargs == NULL) 131 return -ENOMEM; 132 133 length = snprintf(*devargs, length + 1, "%s:%s,%s", 134 busname, devname, drvargs); 135 if (length < 0) { 136 free(*devargs); 137 return -EINVAL; 138 } 139 140 return 0; 141 } 142 143 int 144 rte_eal_hotplug_add(const char *busname, const char *devname, 145 const char *drvargs) 146 { 147 148 char *devargs; 149 int ret; 150 151 ret = build_devargs(busname, devname, drvargs, &devargs); 152 if (ret != 0) 153 return ret; 154 155 ret = rte_dev_probe(devargs); 156 free(devargs); 157 158 return ret; 159 } 160 161 /* probe device at local process. */ 162 int 163 local_dev_probe(const char *devargs, struct rte_device **new_dev) 164 { 165 struct rte_device *dev; 166 struct rte_devargs *da; 167 int ret; 168 169 *new_dev = NULL; 170 da = calloc(1, sizeof(*da)); 171 if (da == NULL) 172 return -ENOMEM; 173 174 ret = rte_devargs_parse(da, devargs); 175 if (ret) 176 goto err_devarg; 177 178 if (da->bus->plug == NULL) { 179 RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n", 180 da->bus->name); 181 ret = -ENOTSUP; 182 goto err_devarg; 183 } 184 185 ret = rte_devargs_insert(&da); 186 if (ret) 187 goto err_devarg; 188 189 /* the rte_devargs will be referenced in the matching rte_device */ 190 ret = da->bus->scan(); 191 if (ret) 192 goto err_devarg; 193 194 dev = da->bus->find_device(NULL, cmp_dev_name, da->name); 195 if (dev == NULL) { 196 RTE_LOG(ERR, EAL, "Cannot find device (%s)\n", 197 da->name); 198 ret = -ENODEV; 199 goto err_devarg; 200 } 201 /* Since there is a matching device, it is now its responsibility 202 * to manage the devargs we've just inserted. From this point 203 * those devargs shouldn't be removed manually anymore. 204 */ 205 206 ret = dev->bus->plug(dev); 207 if (ret > 0) 208 ret = -ENOTSUP; 209 210 if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */ 211 RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n", 212 dev->name); 213 return ret; 214 } 215 216 *new_dev = dev; 217 return ret; 218 219 err_devarg: 220 if (rte_devargs_remove(da) != 0) { 221 rte_devargs_reset(da); 222 free(da); 223 } 224 return ret; 225 } 226 227 int 228 rte_dev_probe(const char *devargs) 229 { 230 struct eal_dev_mp_req req; 231 struct rte_device *dev; 232 int ret; 233 234 memset(&req, 0, sizeof(req)); 235 req.t = EAL_DEV_REQ_TYPE_ATTACH; 236 strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 237 238 if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 239 /** 240 * If in secondary process, just send IPC request to 241 * primary process. 242 */ 243 ret = eal_dev_hotplug_request_to_primary(&req); 244 if (ret != 0) { 245 RTE_LOG(ERR, EAL, 246 "Failed to send hotplug request to primary\n"); 247 return -ENOMSG; 248 } 249 if (req.result != 0) 250 RTE_LOG(ERR, EAL, 251 "Failed to hotplug add device\n"); 252 return req.result; 253 } 254 255 /* attach a shared device from primary start from here: */ 256 257 /* primary attach the new device itself. */ 258 ret = local_dev_probe(devargs, &dev); 259 260 if (ret != 0) { 261 RTE_LOG(ERR, EAL, 262 "Failed to attach device on primary process\n"); 263 264 /** 265 * it is possible that secondary process failed to attached a 266 * device that primary process have during initialization, 267 * so for -EEXIST case, we still need to sync with secondary 268 * process. 269 */ 270 if (ret != -EEXIST) 271 return ret; 272 } 273 274 /* primary send attach sync request to secondary. */ 275 ret = eal_dev_hotplug_request_to_secondary(&req); 276 277 /* if any communication error, we need to rollback. */ 278 if (ret != 0) { 279 RTE_LOG(ERR, EAL, 280 "Failed to send hotplug add request to secondary\n"); 281 ret = -ENOMSG; 282 goto rollback; 283 } 284 285 /** 286 * if any secondary failed to attach, we need to consider if rollback 287 * is necessary. 288 */ 289 if (req.result != 0) { 290 RTE_LOG(ERR, EAL, 291 "Failed to attach device on secondary process\n"); 292 ret = req.result; 293 294 /* for -EEXIST, we don't need to rollback. */ 295 if (ret == -EEXIST) 296 return ret; 297 goto rollback; 298 } 299 300 return 0; 301 302 rollback: 303 req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK; 304 305 /* primary send rollback request to secondary. */ 306 if (eal_dev_hotplug_request_to_secondary(&req) != 0) 307 RTE_LOG(WARNING, EAL, 308 "Failed to rollback device attach on secondary." 309 "Devices in secondary may not sync with primary\n"); 310 311 /* primary rollback itself. */ 312 if (local_dev_remove(dev) != 0) 313 RTE_LOG(WARNING, EAL, 314 "Failed to rollback device attach on primary." 315 "Devices in secondary may not sync with primary\n"); 316 317 return ret; 318 } 319 320 int 321 rte_eal_hotplug_remove(const char *busname, const char *devname) 322 { 323 struct rte_device *dev; 324 struct rte_bus *bus; 325 326 bus = rte_bus_find_by_name(busname); 327 if (bus == NULL) { 328 RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname); 329 return -ENOENT; 330 } 331 332 dev = bus->find_device(NULL, cmp_dev_name, devname); 333 if (dev == NULL) { 334 RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", devname); 335 return -EINVAL; 336 } 337 338 return rte_dev_remove(dev); 339 } 340 341 /* remove device at local process. */ 342 int 343 local_dev_remove(struct rte_device *dev) 344 { 345 int ret; 346 347 if (dev->bus->unplug == NULL) { 348 RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n", 349 dev->bus->name); 350 return -ENOTSUP; 351 } 352 353 ret = dev->bus->unplug(dev); 354 if (ret) { 355 RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n", 356 dev->name); 357 return (ret < 0) ? ret : -ENOENT; 358 } 359 360 return 0; 361 } 362 363 int 364 rte_dev_remove(struct rte_device *dev) 365 { 366 struct eal_dev_mp_req req; 367 char *devargs; 368 int ret; 369 370 if (!rte_dev_is_probed(dev)) { 371 RTE_LOG(ERR, EAL, "Device is not probed\n"); 372 return -ENOENT; 373 } 374 375 ret = build_devargs(dev->bus->name, dev->name, "", &devargs); 376 if (ret != 0) 377 return ret; 378 379 memset(&req, 0, sizeof(req)); 380 req.t = EAL_DEV_REQ_TYPE_DETACH; 381 strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 382 free(devargs); 383 384 if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 385 /** 386 * If in secondary process, just send IPC request to 387 * primary process. 388 */ 389 ret = eal_dev_hotplug_request_to_primary(&req); 390 if (ret != 0) { 391 RTE_LOG(ERR, EAL, 392 "Failed to send hotplug request to primary\n"); 393 return -ENOMSG; 394 } 395 if (req.result != 0) 396 RTE_LOG(ERR, EAL, 397 "Failed to hotplug remove device\n"); 398 return req.result; 399 } 400 401 /* detach a device from primary start from here: */ 402 403 /* primary send detach sync request to secondary */ 404 ret = eal_dev_hotplug_request_to_secondary(&req); 405 406 /** 407 * if communication error, we need to rollback, because it is possible 408 * part of the secondary processes still detached it successfully. 409 */ 410 if (ret != 0) { 411 RTE_LOG(ERR, EAL, 412 "Failed to send device detach request to secondary\n"); 413 ret = -ENOMSG; 414 goto rollback; 415 } 416 417 /** 418 * if any secondary failed to detach, we need to consider if rollback 419 * is necessary. 420 */ 421 if (req.result != 0) { 422 RTE_LOG(ERR, EAL, 423 "Failed to detach device on secondary process\n"); 424 ret = req.result; 425 /** 426 * if -ENOENT, we don't need to rollback, since devices is 427 * already detached on secondary process. 428 */ 429 if (ret != -ENOENT) 430 goto rollback; 431 } 432 433 /* primary detach the device itself. */ 434 ret = local_dev_remove(dev); 435 436 /* if primary failed, still need to consider if rollback is necessary */ 437 if (ret != 0) { 438 RTE_LOG(ERR, EAL, 439 "Failed to detach device on primary process\n"); 440 /* if -ENOENT, we don't need to rollback */ 441 if (ret == -ENOENT) 442 return ret; 443 goto rollback; 444 } 445 446 return 0; 447 448 rollback: 449 req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK; 450 451 /* primary send rollback request to secondary. */ 452 if (eal_dev_hotplug_request_to_secondary(&req) != 0) 453 RTE_LOG(WARNING, EAL, 454 "Failed to rollback device detach on secondary." 455 "Devices in secondary may not sync with primary\n"); 456 457 return ret; 458 } 459 460 int 461 rte_dev_event_callback_register(const char *device_name, 462 rte_dev_event_cb_fn cb_fn, 463 void *cb_arg) 464 { 465 struct dev_event_callback *event_cb; 466 int ret; 467 468 if (!cb_fn) 469 return -EINVAL; 470 471 rte_spinlock_lock(&dev_event_lock); 472 473 if (TAILQ_EMPTY(&dev_event_cbs)) 474 TAILQ_INIT(&dev_event_cbs); 475 476 TAILQ_FOREACH(event_cb, &dev_event_cbs, next) { 477 if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) { 478 if (device_name == NULL && event_cb->dev_name == NULL) 479 break; 480 if (device_name == NULL || event_cb->dev_name == NULL) 481 continue; 482 if (!strcmp(event_cb->dev_name, device_name)) 483 break; 484 } 485 } 486 487 /* create a new callback. */ 488 if (event_cb == NULL) { 489 event_cb = malloc(sizeof(struct dev_event_callback)); 490 if (event_cb != NULL) { 491 event_cb->cb_fn = cb_fn; 492 event_cb->cb_arg = cb_arg; 493 event_cb->active = 0; 494 if (!device_name) { 495 event_cb->dev_name = NULL; 496 } else { 497 event_cb->dev_name = strdup(device_name); 498 if (event_cb->dev_name == NULL) { 499 ret = -ENOMEM; 500 goto error; 501 } 502 } 503 TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next); 504 } else { 505 RTE_LOG(ERR, EAL, 506 "Failed to allocate memory for device " 507 "event callback."); 508 ret = -ENOMEM; 509 goto error; 510 } 511 } else { 512 RTE_LOG(ERR, EAL, 513 "The callback is already exist, no need " 514 "to register again.\n"); 515 event_cb = NULL; 516 ret = -EEXIST; 517 goto error; 518 } 519 520 rte_spinlock_unlock(&dev_event_lock); 521 return 0; 522 error: 523 free(event_cb); 524 rte_spinlock_unlock(&dev_event_lock); 525 return ret; 526 } 527 528 int 529 rte_dev_event_callback_unregister(const char *device_name, 530 rte_dev_event_cb_fn cb_fn, 531 void *cb_arg) 532 { 533 int ret = 0; 534 struct dev_event_callback *event_cb, *next; 535 536 if (!cb_fn) 537 return -EINVAL; 538 539 rte_spinlock_lock(&dev_event_lock); 540 /*walk through the callbacks and remove all that match. */ 541 for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL; 542 event_cb = next) { 543 544 next = TAILQ_NEXT(event_cb, next); 545 546 if (device_name != NULL && event_cb->dev_name != NULL) { 547 if (!strcmp(event_cb->dev_name, device_name)) { 548 if (event_cb->cb_fn != cb_fn || 549 (cb_arg != (void *)-1 && 550 event_cb->cb_arg != cb_arg)) 551 continue; 552 } 553 } else if (device_name != NULL) { 554 continue; 555 } 556 557 /* 558 * if this callback is not executing right now, 559 * then remove it. 560 */ 561 if (event_cb->active == 0) { 562 TAILQ_REMOVE(&dev_event_cbs, event_cb, next); 563 free(event_cb->dev_name); 564 free(event_cb); 565 ret++; 566 } else { 567 ret = -EAGAIN; 568 break; 569 } 570 } 571 572 /* this callback is not be registered */ 573 if (ret == 0) 574 ret = -ENOENT; 575 576 rte_spinlock_unlock(&dev_event_lock); 577 return ret; 578 } 579 580 void 581 rte_dev_event_callback_process(const char *device_name, 582 enum rte_dev_event_type event) 583 { 584 struct dev_event_callback *cb_lst; 585 586 if (device_name == NULL) 587 return; 588 589 rte_spinlock_lock(&dev_event_lock); 590 591 TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) { 592 if (cb_lst->dev_name) { 593 if (strcmp(cb_lst->dev_name, device_name)) 594 continue; 595 } 596 cb_lst->active = 1; 597 rte_spinlock_unlock(&dev_event_lock); 598 cb_lst->cb_fn(device_name, event, 599 cb_lst->cb_arg); 600 rte_spinlock_lock(&dev_event_lock); 601 cb_lst->active = 0; 602 } 603 rte_spinlock_unlock(&dev_event_lock); 604 } 605 606 int 607 rte_dev_iterator_init(struct rte_dev_iterator *it, 608 const char *dev_str) 609 { 610 struct rte_devargs devargs = { .bus = NULL }; 611 struct rte_class *cls = NULL; 612 struct rte_bus *bus = NULL; 613 614 /* Having both bus_str and cls_str NULL is illegal, 615 * marking this iterator as invalid unless 616 * everything goes well. 617 */ 618 it->bus_str = NULL; 619 it->cls_str = NULL; 620 621 /* Setting data field implies no malloc in parsing. */ 622 devargs.data = (void *)(intptr_t)dev_str; 623 if (rte_devargs_layers_parse(&devargs, dev_str)) 624 goto get_out; 625 626 bus = devargs.bus; 627 cls = devargs.cls; 628 /* The string should have at least 629 * one layer specified. 630 */ 631 if (bus == NULL && cls == NULL) { 632 RTE_LOG(DEBUG, EAL, "Either bus or class must be specified.\n"); 633 rte_errno = EINVAL; 634 goto get_out; 635 } 636 if (bus != NULL && bus->dev_iterate == NULL) { 637 RTE_LOG(DEBUG, EAL, "Bus %s not supported\n", bus->name); 638 rte_errno = ENOTSUP; 639 goto get_out; 640 } 641 if (cls != NULL && cls->dev_iterate == NULL) { 642 RTE_LOG(DEBUG, EAL, "Class %s not supported\n", cls->name); 643 rte_errno = ENOTSUP; 644 goto get_out; 645 } 646 it->bus_str = devargs.bus_str; 647 it->cls_str = devargs.cls_str; 648 it->dev_str = dev_str; 649 it->bus = bus; 650 it->cls = cls; 651 it->device = NULL; 652 it->class_device = NULL; 653 get_out: 654 return -rte_errno; 655 } 656 657 static char * 658 dev_str_sane_copy(const char *str) 659 { 660 size_t end; 661 char *copy; 662 663 end = strcspn(str, ",/"); 664 if (str[end] == ',') { 665 copy = strdup(&str[end + 1]); 666 } else { 667 /* '/' or '\0' */ 668 copy = strdup(""); 669 } 670 if (copy == NULL) { 671 rte_errno = ENOMEM; 672 } else { 673 char *slash; 674 675 slash = strchr(copy, '/'); 676 if (slash != NULL) 677 slash[0] = '\0'; 678 } 679 return copy; 680 } 681 682 static int 683 class_next_dev_cmp(const struct rte_class *cls, 684 const void *ctx) 685 { 686 struct rte_dev_iterator *it; 687 const char *cls_str = NULL; 688 void *dev; 689 690 if (cls->dev_iterate == NULL) 691 return 1; 692 it = ITCTX(ctx); 693 cls_str = CLSCTX(ctx); 694 dev = it->class_device; 695 /* it->cls_str != NULL means a class 696 * was specified in the devstr. 697 */ 698 if (it->cls_str != NULL && cls != it->cls) 699 return 1; 700 /* If an error occurred previously, 701 * no need to test further. 702 */ 703 if (rte_errno != 0) 704 return -1; 705 dev = cls->dev_iterate(dev, cls_str, it); 706 it->class_device = dev; 707 return dev == NULL; 708 } 709 710 static int 711 bus_next_dev_cmp(const struct rte_bus *bus, 712 const void *ctx) 713 { 714 struct rte_device *dev = NULL; 715 struct rte_class *cls = NULL; 716 struct rte_dev_iterator *it; 717 const char *bus_str = NULL; 718 719 if (bus->dev_iterate == NULL) 720 return 1; 721 it = ITCTX(ctx); 722 bus_str = BUSCTX(ctx); 723 dev = it->device; 724 /* it->bus_str != NULL means a bus 725 * was specified in the devstr. 726 */ 727 if (it->bus_str != NULL && bus != it->bus) 728 return 1; 729 /* If an error occurred previously, 730 * no need to test further. 731 */ 732 if (rte_errno != 0) 733 return -1; 734 if (it->cls_str == NULL) { 735 dev = bus->dev_iterate(dev, bus_str, it); 736 goto end; 737 } 738 /* cls_str != NULL */ 739 if (dev == NULL) { 740 next_dev_on_bus: 741 dev = bus->dev_iterate(dev, bus_str, it); 742 it->device = dev; 743 } 744 if (dev == NULL) 745 return 1; 746 if (it->cls != NULL) 747 cls = TAILQ_PREV(it->cls, rte_class_list, next); 748 cls = rte_class_find(cls, class_next_dev_cmp, ctx); 749 if (cls != NULL) { 750 it->cls = cls; 751 goto end; 752 } 753 goto next_dev_on_bus; 754 end: 755 it->device = dev; 756 return dev == NULL; 757 } 758 struct rte_device * 759 rte_dev_iterator_next(struct rte_dev_iterator *it) 760 { 761 struct rte_bus *bus = NULL; 762 int old_errno = rte_errno; 763 char *bus_str = NULL; 764 char *cls_str = NULL; 765 766 rte_errno = 0; 767 if (it->bus_str == NULL && it->cls_str == NULL) { 768 /* Invalid iterator. */ 769 rte_errno = EINVAL; 770 return NULL; 771 } 772 if (it->bus != NULL) 773 bus = TAILQ_PREV(it->bus, rte_bus_list, next); 774 if (it->bus_str != NULL) { 775 bus_str = dev_str_sane_copy(it->bus_str); 776 if (bus_str == NULL) 777 goto out; 778 } 779 if (it->cls_str != NULL) { 780 cls_str = dev_str_sane_copy(it->cls_str); 781 if (cls_str == NULL) 782 goto out; 783 } 784 while ((bus = rte_bus_find(bus, bus_next_dev_cmp, 785 CTX(it, bus_str, cls_str)))) { 786 if (it->device != NULL) { 787 it->bus = bus; 788 goto out; 789 } 790 if (it->bus_str != NULL || 791 rte_errno != 0) 792 break; 793 } 794 if (rte_errno == 0) 795 rte_errno = old_errno; 796 out: 797 free(bus_str); 798 free(cls_str); 799 return it->device; 800 } 801 802 int 803 rte_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, 804 size_t len) 805 { 806 if (dev->bus->dma_map == NULL || len == 0) { 807 rte_errno = ENOTSUP; 808 return -1; 809 } 810 /* Memory must be registered through rte_extmem_* APIs */ 811 if (rte_mem_virt2memseg_list(addr) == NULL) { 812 rte_errno = EINVAL; 813 return -1; 814 } 815 816 return dev->bus->dma_map(dev, addr, iova, len); 817 } 818 819 int 820 rte_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, 821 size_t len) 822 { 823 if (dev->bus->dma_unmap == NULL || len == 0) { 824 rte_errno = ENOTSUP; 825 return -1; 826 } 827 /* Memory must be registered through rte_extmem_* APIs */ 828 if (rte_mem_virt2memseg_list(addr) == NULL) { 829 rte_errno = EINVAL; 830 return -1; 831 } 832 833 return dev->bus->dma_unmap(dev, addr, iova, len); 834 } 835