199a2dd95SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 299a2dd95SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation. 399a2dd95SBruce Richardson * Copyright(c) 2014 6WIND S.A. 499a2dd95SBruce Richardson */ 599a2dd95SBruce Richardson 699a2dd95SBruce Richardson #include <stdio.h> 772b452c5SDmitry Kozlyuk #include <stdlib.h> 899a2dd95SBruce Richardson #include <string.h> 999a2dd95SBruce Richardson #include <sys/queue.h> 1099a2dd95SBruce Richardson 11a04322f6SDavid Marchand #include <bus_driver.h> 1299a2dd95SBruce Richardson #include <rte_class.h> 1399a2dd95SBruce Richardson #include <rte_dev.h> 1499a2dd95SBruce Richardson #include <rte_devargs.h> 1599a2dd95SBruce Richardson #include <rte_errno.h> 1699a2dd95SBruce Richardson #include <rte_log.h> 1799a2dd95SBruce Richardson #include <rte_spinlock.h> 1899a2dd95SBruce Richardson #include <rte_string_fns.h> 1999a2dd95SBruce Richardson 2099a2dd95SBruce Richardson #include "eal_private.h" 2199a2dd95SBruce Richardson #include "hotplug_mp.h" 2299a2dd95SBruce Richardson 23*97bbdba3SDavid Marchand const char * 24*97bbdba3SDavid Marchand rte_driver_name(const struct rte_driver *driver) 25*97bbdba3SDavid Marchand { 26*97bbdba3SDavid Marchand return driver->name; 27*97bbdba3SDavid Marchand } 28*97bbdba3SDavid Marchand 2999a2dd95SBruce Richardson /** 3099a2dd95SBruce Richardson * The device event callback description. 3199a2dd95SBruce Richardson * 3299a2dd95SBruce Richardson * It contains callback address to be registered by user application, 3399a2dd95SBruce Richardson * the pointer to the parameters for callback, and the device name. 3499a2dd95SBruce Richardson */ 3599a2dd95SBruce Richardson struct dev_event_callback { 3699a2dd95SBruce Richardson TAILQ_ENTRY(dev_event_callback) next; /**< Callbacks list */ 3799a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn; /**< Callback address */ 3899a2dd95SBruce Richardson void *cb_arg; /**< Callback parameter */ 3999a2dd95SBruce Richardson char *dev_name; /**< Callback device name, NULL is for all device */ 4099a2dd95SBruce Richardson uint32_t active; /**< Callback is executing */ 4199a2dd95SBruce Richardson }; 4299a2dd95SBruce Richardson 4399a2dd95SBruce Richardson /** @internal Structure to keep track of registered callbacks */ 4499a2dd95SBruce Richardson TAILQ_HEAD(dev_event_cb_list, dev_event_callback); 4599a2dd95SBruce Richardson 4699a2dd95SBruce Richardson /* The device event callback list for all registered callbacks. */ 4799a2dd95SBruce Richardson static struct dev_event_cb_list dev_event_cbs; 4899a2dd95SBruce Richardson 4999a2dd95SBruce Richardson /* spinlock for device callbacks */ 5099a2dd95SBruce Richardson static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER; 5199a2dd95SBruce Richardson 5299a2dd95SBruce Richardson struct dev_next_ctx { 5399a2dd95SBruce Richardson struct rte_dev_iterator *it; 5499a2dd95SBruce Richardson const char *bus_str; 5599a2dd95SBruce Richardson const char *cls_str; 5699a2dd95SBruce Richardson }; 5799a2dd95SBruce Richardson 5899a2dd95SBruce Richardson #define CTX(it, bus_str, cls_str) \ 5999a2dd95SBruce Richardson (&(const struct dev_next_ctx){ \ 6099a2dd95SBruce Richardson .it = it, \ 6199a2dd95SBruce Richardson .bus_str = bus_str, \ 6299a2dd95SBruce Richardson .cls_str = cls_str, \ 6399a2dd95SBruce Richardson }) 6499a2dd95SBruce Richardson 6599a2dd95SBruce Richardson #define ITCTX(ptr) \ 6699a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->it) 6799a2dd95SBruce Richardson 6899a2dd95SBruce Richardson #define BUSCTX(ptr) \ 6999a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->bus_str) 7099a2dd95SBruce Richardson 7199a2dd95SBruce Richardson #define CLSCTX(ptr) \ 7299a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->cls_str) 7399a2dd95SBruce Richardson 7499a2dd95SBruce Richardson static int cmp_dev_name(const struct rte_device *dev, const void *_name) 7599a2dd95SBruce Richardson { 7699a2dd95SBruce Richardson const char *name = _name; 7799a2dd95SBruce Richardson 7899a2dd95SBruce Richardson return strcmp(dev->name, name); 7999a2dd95SBruce Richardson } 8099a2dd95SBruce Richardson 8199a2dd95SBruce Richardson int 8299a2dd95SBruce Richardson rte_dev_is_probed(const struct rte_device *dev) 8399a2dd95SBruce Richardson { 8499a2dd95SBruce Richardson /* The field driver should be set only when the probe is successful. */ 8599a2dd95SBruce Richardson return dev->driver != NULL; 8699a2dd95SBruce Richardson } 8799a2dd95SBruce Richardson 8899a2dd95SBruce Richardson /* helper function to build devargs, caller should free the memory */ 8999a2dd95SBruce Richardson static int 9099a2dd95SBruce Richardson build_devargs(const char *busname, const char *devname, 9199a2dd95SBruce Richardson const char *drvargs, char **devargs) 9299a2dd95SBruce Richardson { 9399a2dd95SBruce Richardson int length; 9499a2dd95SBruce Richardson 9599a2dd95SBruce Richardson length = snprintf(NULL, 0, "%s:%s,%s", busname, devname, drvargs); 9699a2dd95SBruce Richardson if (length < 0) 9799a2dd95SBruce Richardson return -EINVAL; 9899a2dd95SBruce Richardson 9999a2dd95SBruce Richardson *devargs = malloc(length + 1); 10099a2dd95SBruce Richardson if (*devargs == NULL) 10199a2dd95SBruce Richardson return -ENOMEM; 10299a2dd95SBruce Richardson 10399a2dd95SBruce Richardson length = snprintf(*devargs, length + 1, "%s:%s,%s", 10499a2dd95SBruce Richardson busname, devname, drvargs); 10599a2dd95SBruce Richardson if (length < 0) { 10699a2dd95SBruce Richardson free(*devargs); 10799a2dd95SBruce Richardson return -EINVAL; 10899a2dd95SBruce Richardson } 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson return 0; 11199a2dd95SBruce Richardson } 11299a2dd95SBruce Richardson 11399a2dd95SBruce Richardson int 11499a2dd95SBruce Richardson rte_eal_hotplug_add(const char *busname, const char *devname, 11599a2dd95SBruce Richardson const char *drvargs) 11699a2dd95SBruce Richardson { 11799a2dd95SBruce Richardson 11899a2dd95SBruce Richardson char *devargs; 11999a2dd95SBruce Richardson int ret; 12099a2dd95SBruce Richardson 12199a2dd95SBruce Richardson ret = build_devargs(busname, devname, drvargs, &devargs); 12299a2dd95SBruce Richardson if (ret != 0) 12399a2dd95SBruce Richardson return ret; 12499a2dd95SBruce Richardson 12599a2dd95SBruce Richardson ret = rte_dev_probe(devargs); 12699a2dd95SBruce Richardson free(devargs); 12799a2dd95SBruce Richardson 12899a2dd95SBruce Richardson return ret; 12999a2dd95SBruce Richardson } 13099a2dd95SBruce Richardson 13199a2dd95SBruce Richardson /* probe device at local process. */ 13299a2dd95SBruce Richardson int 13399a2dd95SBruce Richardson local_dev_probe(const char *devargs, struct rte_device **new_dev) 13499a2dd95SBruce Richardson { 13599a2dd95SBruce Richardson struct rte_device *dev; 13699a2dd95SBruce Richardson struct rte_devargs *da; 13799a2dd95SBruce Richardson int ret; 13899a2dd95SBruce Richardson 13999a2dd95SBruce Richardson *new_dev = NULL; 14099a2dd95SBruce Richardson da = calloc(1, sizeof(*da)); 14199a2dd95SBruce Richardson if (da == NULL) 14299a2dd95SBruce Richardson return -ENOMEM; 14399a2dd95SBruce Richardson 14499a2dd95SBruce Richardson ret = rte_devargs_parse(da, devargs); 14599a2dd95SBruce Richardson if (ret) 14699a2dd95SBruce Richardson goto err_devarg; 14799a2dd95SBruce Richardson 14899a2dd95SBruce Richardson if (da->bus->plug == NULL) { 14999a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Function plug not supported by bus (%s)\n", 15099a2dd95SBruce Richardson da->bus->name); 15199a2dd95SBruce Richardson ret = -ENOTSUP; 15299a2dd95SBruce Richardson goto err_devarg; 15399a2dd95SBruce Richardson } 15499a2dd95SBruce Richardson 15599a2dd95SBruce Richardson ret = rte_devargs_insert(&da); 15699a2dd95SBruce Richardson if (ret) 15799a2dd95SBruce Richardson goto err_devarg; 15899a2dd95SBruce Richardson 15999a2dd95SBruce Richardson /* the rte_devargs will be referenced in the matching rte_device */ 16099a2dd95SBruce Richardson ret = da->bus->scan(); 16199a2dd95SBruce Richardson if (ret) 16299a2dd95SBruce Richardson goto err_devarg; 16399a2dd95SBruce Richardson 16499a2dd95SBruce Richardson dev = da->bus->find_device(NULL, cmp_dev_name, da->name); 16599a2dd95SBruce Richardson if (dev == NULL) { 16699a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Cannot find device (%s)\n", 16799a2dd95SBruce Richardson da->name); 16899a2dd95SBruce Richardson ret = -ENODEV; 16999a2dd95SBruce Richardson goto err_devarg; 17099a2dd95SBruce Richardson } 17199a2dd95SBruce Richardson /* Since there is a matching device, it is now its responsibility 17299a2dd95SBruce Richardson * to manage the devargs we've just inserted. From this point 17399a2dd95SBruce Richardson * those devargs shouldn't be removed manually anymore. 17499a2dd95SBruce Richardson */ 17599a2dd95SBruce Richardson 17699a2dd95SBruce Richardson ret = dev->bus->plug(dev); 17799a2dd95SBruce Richardson if (ret > 0) 17899a2dd95SBruce Richardson ret = -ENOTSUP; 17999a2dd95SBruce Richardson 18099a2dd95SBruce Richardson if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */ 18199a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Driver cannot attach the device (%s)\n", 18299a2dd95SBruce Richardson dev->name); 18399a2dd95SBruce Richardson return ret; 18499a2dd95SBruce Richardson } 18599a2dd95SBruce Richardson 18699a2dd95SBruce Richardson *new_dev = dev; 18799a2dd95SBruce Richardson return ret; 18899a2dd95SBruce Richardson 18999a2dd95SBruce Richardson err_devarg: 19026d734b5SDavid Marchand if (rte_devargs_remove(da) != 0) { 19199a2dd95SBruce Richardson rte_devargs_reset(da); 19226d734b5SDavid Marchand free(da); 19326d734b5SDavid Marchand } 19499a2dd95SBruce Richardson return ret; 19599a2dd95SBruce Richardson } 19699a2dd95SBruce Richardson 19799a2dd95SBruce Richardson int 19899a2dd95SBruce Richardson rte_dev_probe(const char *devargs) 19999a2dd95SBruce Richardson { 20099a2dd95SBruce Richardson struct eal_dev_mp_req req; 20199a2dd95SBruce Richardson struct rte_device *dev; 20299a2dd95SBruce Richardson int ret; 20399a2dd95SBruce Richardson 20499a2dd95SBruce Richardson memset(&req, 0, sizeof(req)); 20599a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_ATTACH; 20699a2dd95SBruce Richardson strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 20799a2dd95SBruce Richardson 20899a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 20999a2dd95SBruce Richardson /** 21099a2dd95SBruce Richardson * If in secondary process, just send IPC request to 21199a2dd95SBruce Richardson * primary process. 21299a2dd95SBruce Richardson */ 21399a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_primary(&req); 21499a2dd95SBruce Richardson if (ret != 0) { 21599a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 21699a2dd95SBruce Richardson "Failed to send hotplug request to primary\n"); 21799a2dd95SBruce Richardson return -ENOMSG; 21899a2dd95SBruce Richardson } 21999a2dd95SBruce Richardson if (req.result != 0) 22099a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 22199a2dd95SBruce Richardson "Failed to hotplug add device\n"); 22299a2dd95SBruce Richardson return req.result; 22399a2dd95SBruce Richardson } 22499a2dd95SBruce Richardson 22599a2dd95SBruce Richardson /* attach a shared device from primary start from here: */ 22699a2dd95SBruce Richardson 22799a2dd95SBruce Richardson /* primary attach the new device itself. */ 22899a2dd95SBruce Richardson ret = local_dev_probe(devargs, &dev); 22999a2dd95SBruce Richardson 23099a2dd95SBruce Richardson if (ret != 0) { 23199a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 23299a2dd95SBruce Richardson "Failed to attach device on primary process\n"); 23399a2dd95SBruce Richardson 23499a2dd95SBruce Richardson /** 23599a2dd95SBruce Richardson * it is possible that secondary process failed to attached a 23699a2dd95SBruce Richardson * device that primary process have during initialization, 23799a2dd95SBruce Richardson * so for -EEXIST case, we still need to sync with secondary 23899a2dd95SBruce Richardson * process. 23999a2dd95SBruce Richardson */ 24099a2dd95SBruce Richardson if (ret != -EEXIST) 24199a2dd95SBruce Richardson return ret; 24299a2dd95SBruce Richardson } 24399a2dd95SBruce Richardson 24499a2dd95SBruce Richardson /* primary send attach sync request to secondary. */ 24599a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_secondary(&req); 24699a2dd95SBruce Richardson 24799a2dd95SBruce Richardson /* if any communication error, we need to rollback. */ 24899a2dd95SBruce Richardson if (ret != 0) { 24999a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 25099a2dd95SBruce Richardson "Failed to send hotplug add request to secondary\n"); 25199a2dd95SBruce Richardson ret = -ENOMSG; 25299a2dd95SBruce Richardson goto rollback; 25399a2dd95SBruce Richardson } 25499a2dd95SBruce Richardson 25599a2dd95SBruce Richardson /** 25699a2dd95SBruce Richardson * if any secondary failed to attach, we need to consider if rollback 25799a2dd95SBruce Richardson * is necessary. 25899a2dd95SBruce Richardson */ 25999a2dd95SBruce Richardson if (req.result != 0) { 26099a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 26199a2dd95SBruce Richardson "Failed to attach device on secondary process\n"); 26299a2dd95SBruce Richardson ret = req.result; 26399a2dd95SBruce Richardson 26499a2dd95SBruce Richardson /* for -EEXIST, we don't need to rollback. */ 26599a2dd95SBruce Richardson if (ret == -EEXIST) 26699a2dd95SBruce Richardson return ret; 26799a2dd95SBruce Richardson goto rollback; 26899a2dd95SBruce Richardson } 26999a2dd95SBruce Richardson 27099a2dd95SBruce Richardson return 0; 27199a2dd95SBruce Richardson 27299a2dd95SBruce Richardson rollback: 27399a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK; 27499a2dd95SBruce Richardson 27599a2dd95SBruce Richardson /* primary send rollback request to secondary. */ 27699a2dd95SBruce Richardson if (eal_dev_hotplug_request_to_secondary(&req) != 0) 27799a2dd95SBruce Richardson RTE_LOG(WARNING, EAL, 27899a2dd95SBruce Richardson "Failed to rollback device attach on secondary." 27999a2dd95SBruce Richardson "Devices in secondary may not sync with primary\n"); 28099a2dd95SBruce Richardson 28199a2dd95SBruce Richardson /* primary rollback itself. */ 28299a2dd95SBruce Richardson if (local_dev_remove(dev) != 0) 28399a2dd95SBruce Richardson RTE_LOG(WARNING, EAL, 28499a2dd95SBruce Richardson "Failed to rollback device attach on primary." 28599a2dd95SBruce Richardson "Devices in secondary may not sync with primary\n"); 28699a2dd95SBruce Richardson 28799a2dd95SBruce Richardson return ret; 28899a2dd95SBruce Richardson } 28999a2dd95SBruce Richardson 29099a2dd95SBruce Richardson int 29199a2dd95SBruce Richardson rte_eal_hotplug_remove(const char *busname, const char *devname) 29299a2dd95SBruce Richardson { 29399a2dd95SBruce Richardson struct rte_device *dev; 29499a2dd95SBruce Richardson struct rte_bus *bus; 29599a2dd95SBruce Richardson 29699a2dd95SBruce Richardson bus = rte_bus_find_by_name(busname); 29799a2dd95SBruce Richardson if (bus == NULL) { 29899a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Cannot find bus (%s)\n", busname); 29999a2dd95SBruce Richardson return -ENOENT; 30099a2dd95SBruce Richardson } 30199a2dd95SBruce Richardson 30299a2dd95SBruce Richardson dev = bus->find_device(NULL, cmp_dev_name, devname); 30399a2dd95SBruce Richardson if (dev == NULL) { 30499a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Cannot find plugged device (%s)\n", devname); 30599a2dd95SBruce Richardson return -EINVAL; 30699a2dd95SBruce Richardson } 30799a2dd95SBruce Richardson 30899a2dd95SBruce Richardson return rte_dev_remove(dev); 30999a2dd95SBruce Richardson } 31099a2dd95SBruce Richardson 31199a2dd95SBruce Richardson /* remove device at local process. */ 31299a2dd95SBruce Richardson int 31399a2dd95SBruce Richardson local_dev_remove(struct rte_device *dev) 31499a2dd95SBruce Richardson { 31599a2dd95SBruce Richardson int ret; 31699a2dd95SBruce Richardson 31799a2dd95SBruce Richardson if (dev->bus->unplug == NULL) { 31899a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Function unplug not supported by bus (%s)\n", 31999a2dd95SBruce Richardson dev->bus->name); 32099a2dd95SBruce Richardson return -ENOTSUP; 32199a2dd95SBruce Richardson } 32299a2dd95SBruce Richardson 32399a2dd95SBruce Richardson ret = dev->bus->unplug(dev); 32499a2dd95SBruce Richardson if (ret) { 32599a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Driver cannot detach the device (%s)\n", 32699a2dd95SBruce Richardson dev->name); 32799a2dd95SBruce Richardson return (ret < 0) ? ret : -ENOENT; 32899a2dd95SBruce Richardson } 32999a2dd95SBruce Richardson 33099a2dd95SBruce Richardson return 0; 33199a2dd95SBruce Richardson } 33299a2dd95SBruce Richardson 33399a2dd95SBruce Richardson int 33499a2dd95SBruce Richardson rte_dev_remove(struct rte_device *dev) 33599a2dd95SBruce Richardson { 33699a2dd95SBruce Richardson struct eal_dev_mp_req req; 33799a2dd95SBruce Richardson char *devargs; 33899a2dd95SBruce Richardson int ret; 33999a2dd95SBruce Richardson 34099a2dd95SBruce Richardson if (!rte_dev_is_probed(dev)) { 34199a2dd95SBruce Richardson RTE_LOG(ERR, EAL, "Device is not probed\n"); 34299a2dd95SBruce Richardson return -ENOENT; 34399a2dd95SBruce Richardson } 34499a2dd95SBruce Richardson 34599a2dd95SBruce Richardson ret = build_devargs(dev->bus->name, dev->name, "", &devargs); 34699a2dd95SBruce Richardson if (ret != 0) 34799a2dd95SBruce Richardson return ret; 34899a2dd95SBruce Richardson 34999a2dd95SBruce Richardson memset(&req, 0, sizeof(req)); 35099a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_DETACH; 35199a2dd95SBruce Richardson strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 35299a2dd95SBruce Richardson free(devargs); 35399a2dd95SBruce Richardson 35499a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 35599a2dd95SBruce Richardson /** 35699a2dd95SBruce Richardson * If in secondary process, just send IPC request to 35799a2dd95SBruce Richardson * primary process. 35899a2dd95SBruce Richardson */ 35999a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_primary(&req); 36099a2dd95SBruce Richardson if (ret != 0) { 36199a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 36299a2dd95SBruce Richardson "Failed to send hotplug request to primary\n"); 36399a2dd95SBruce Richardson return -ENOMSG; 36499a2dd95SBruce Richardson } 36599a2dd95SBruce Richardson if (req.result != 0) 36699a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 36799a2dd95SBruce Richardson "Failed to hotplug remove device\n"); 36899a2dd95SBruce Richardson return req.result; 36999a2dd95SBruce Richardson } 37099a2dd95SBruce Richardson 37199a2dd95SBruce Richardson /* detach a device from primary start from here: */ 37299a2dd95SBruce Richardson 37399a2dd95SBruce Richardson /* primary send detach sync request to secondary */ 37499a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_secondary(&req); 37599a2dd95SBruce Richardson 37699a2dd95SBruce Richardson /** 37799a2dd95SBruce Richardson * if communication error, we need to rollback, because it is possible 37899a2dd95SBruce Richardson * part of the secondary processes still detached it successfully. 37999a2dd95SBruce Richardson */ 38099a2dd95SBruce Richardson if (ret != 0) { 38199a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 38299a2dd95SBruce Richardson "Failed to send device detach request to secondary\n"); 38399a2dd95SBruce Richardson ret = -ENOMSG; 38499a2dd95SBruce Richardson goto rollback; 38599a2dd95SBruce Richardson } 38699a2dd95SBruce Richardson 38799a2dd95SBruce Richardson /** 38899a2dd95SBruce Richardson * if any secondary failed to detach, we need to consider if rollback 38999a2dd95SBruce Richardson * is necessary. 39099a2dd95SBruce Richardson */ 39199a2dd95SBruce Richardson if (req.result != 0) { 39299a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 39399a2dd95SBruce Richardson "Failed to detach device on secondary process\n"); 39499a2dd95SBruce Richardson ret = req.result; 39599a2dd95SBruce Richardson /** 39699a2dd95SBruce Richardson * if -ENOENT, we don't need to rollback, since devices is 39799a2dd95SBruce Richardson * already detached on secondary process. 39899a2dd95SBruce Richardson */ 39999a2dd95SBruce Richardson if (ret != -ENOENT) 40099a2dd95SBruce Richardson goto rollback; 40199a2dd95SBruce Richardson } 40299a2dd95SBruce Richardson 40399a2dd95SBruce Richardson /* primary detach the device itself. */ 40499a2dd95SBruce Richardson ret = local_dev_remove(dev); 40599a2dd95SBruce Richardson 40699a2dd95SBruce Richardson /* if primary failed, still need to consider if rollback is necessary */ 40799a2dd95SBruce Richardson if (ret != 0) { 40899a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 40999a2dd95SBruce Richardson "Failed to detach device on primary process\n"); 41099a2dd95SBruce Richardson /* if -ENOENT, we don't need to rollback */ 41199a2dd95SBruce Richardson if (ret == -ENOENT) 41299a2dd95SBruce Richardson return ret; 41399a2dd95SBruce Richardson goto rollback; 41499a2dd95SBruce Richardson } 41599a2dd95SBruce Richardson 41699a2dd95SBruce Richardson return 0; 41799a2dd95SBruce Richardson 41899a2dd95SBruce Richardson rollback: 41999a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK; 42099a2dd95SBruce Richardson 42199a2dd95SBruce Richardson /* primary send rollback request to secondary. */ 42299a2dd95SBruce Richardson if (eal_dev_hotplug_request_to_secondary(&req) != 0) 42399a2dd95SBruce Richardson RTE_LOG(WARNING, EAL, 42499a2dd95SBruce Richardson "Failed to rollback device detach on secondary." 42599a2dd95SBruce Richardson "Devices in secondary may not sync with primary\n"); 42699a2dd95SBruce Richardson 42799a2dd95SBruce Richardson return ret; 42899a2dd95SBruce Richardson } 42999a2dd95SBruce Richardson 43099a2dd95SBruce Richardson int 43199a2dd95SBruce Richardson rte_dev_event_callback_register(const char *device_name, 43299a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn, 43399a2dd95SBruce Richardson void *cb_arg) 43499a2dd95SBruce Richardson { 43599a2dd95SBruce Richardson struct dev_event_callback *event_cb; 43699a2dd95SBruce Richardson int ret; 43799a2dd95SBruce Richardson 43899a2dd95SBruce Richardson if (!cb_fn) 43999a2dd95SBruce Richardson return -EINVAL; 44099a2dd95SBruce Richardson 44199a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 44299a2dd95SBruce Richardson 44399a2dd95SBruce Richardson if (TAILQ_EMPTY(&dev_event_cbs)) 44499a2dd95SBruce Richardson TAILQ_INIT(&dev_event_cbs); 44599a2dd95SBruce Richardson 44699a2dd95SBruce Richardson TAILQ_FOREACH(event_cb, &dev_event_cbs, next) { 44799a2dd95SBruce Richardson if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) { 44899a2dd95SBruce Richardson if (device_name == NULL && event_cb->dev_name == NULL) 44999a2dd95SBruce Richardson break; 45099a2dd95SBruce Richardson if (device_name == NULL || event_cb->dev_name == NULL) 45199a2dd95SBruce Richardson continue; 45299a2dd95SBruce Richardson if (!strcmp(event_cb->dev_name, device_name)) 45399a2dd95SBruce Richardson break; 45499a2dd95SBruce Richardson } 45599a2dd95SBruce Richardson } 45699a2dd95SBruce Richardson 45799a2dd95SBruce Richardson /* create a new callback. */ 45899a2dd95SBruce Richardson if (event_cb == NULL) { 45999a2dd95SBruce Richardson event_cb = malloc(sizeof(struct dev_event_callback)); 46099a2dd95SBruce Richardson if (event_cb != NULL) { 46199a2dd95SBruce Richardson event_cb->cb_fn = cb_fn; 46299a2dd95SBruce Richardson event_cb->cb_arg = cb_arg; 46399a2dd95SBruce Richardson event_cb->active = 0; 46499a2dd95SBruce Richardson if (!device_name) { 46599a2dd95SBruce Richardson event_cb->dev_name = NULL; 46699a2dd95SBruce Richardson } else { 46799a2dd95SBruce Richardson event_cb->dev_name = strdup(device_name); 46899a2dd95SBruce Richardson if (event_cb->dev_name == NULL) { 46999a2dd95SBruce Richardson ret = -ENOMEM; 47099a2dd95SBruce Richardson goto error; 47199a2dd95SBruce Richardson } 47299a2dd95SBruce Richardson } 47399a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next); 47499a2dd95SBruce Richardson } else { 47599a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 47699a2dd95SBruce Richardson "Failed to allocate memory for device " 47799a2dd95SBruce Richardson "event callback."); 47899a2dd95SBruce Richardson ret = -ENOMEM; 47999a2dd95SBruce Richardson goto error; 48099a2dd95SBruce Richardson } 48199a2dd95SBruce Richardson } else { 48299a2dd95SBruce Richardson RTE_LOG(ERR, EAL, 48399a2dd95SBruce Richardson "The callback is already exist, no need " 48499a2dd95SBruce Richardson "to register again.\n"); 48599a2dd95SBruce Richardson event_cb = NULL; 48699a2dd95SBruce Richardson ret = -EEXIST; 48799a2dd95SBruce Richardson goto error; 48899a2dd95SBruce Richardson } 48999a2dd95SBruce Richardson 49099a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 49199a2dd95SBruce Richardson return 0; 49299a2dd95SBruce Richardson error: 49399a2dd95SBruce Richardson free(event_cb); 49499a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 49599a2dd95SBruce Richardson return ret; 49699a2dd95SBruce Richardson } 49799a2dd95SBruce Richardson 49899a2dd95SBruce Richardson int 49999a2dd95SBruce Richardson rte_dev_event_callback_unregister(const char *device_name, 50099a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn, 50199a2dd95SBruce Richardson void *cb_arg) 50299a2dd95SBruce Richardson { 50399a2dd95SBruce Richardson int ret = 0; 50499a2dd95SBruce Richardson struct dev_event_callback *event_cb, *next; 50599a2dd95SBruce Richardson 50699a2dd95SBruce Richardson if (!cb_fn) 50799a2dd95SBruce Richardson return -EINVAL; 50899a2dd95SBruce Richardson 50999a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 51099a2dd95SBruce Richardson /*walk through the callbacks and remove all that match. */ 51199a2dd95SBruce Richardson for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL; 51299a2dd95SBruce Richardson event_cb = next) { 51399a2dd95SBruce Richardson 51499a2dd95SBruce Richardson next = TAILQ_NEXT(event_cb, next); 51599a2dd95SBruce Richardson 51699a2dd95SBruce Richardson if (device_name != NULL && event_cb->dev_name != NULL) { 51799a2dd95SBruce Richardson if (!strcmp(event_cb->dev_name, device_name)) { 51899a2dd95SBruce Richardson if (event_cb->cb_fn != cb_fn || 51999a2dd95SBruce Richardson (cb_arg != (void *)-1 && 52099a2dd95SBruce Richardson event_cb->cb_arg != cb_arg)) 52199a2dd95SBruce Richardson continue; 52299a2dd95SBruce Richardson } 52399a2dd95SBruce Richardson } else if (device_name != NULL) { 52499a2dd95SBruce Richardson continue; 52599a2dd95SBruce Richardson } 52699a2dd95SBruce Richardson 52799a2dd95SBruce Richardson /* 52899a2dd95SBruce Richardson * if this callback is not executing right now, 52999a2dd95SBruce Richardson * then remove it. 53099a2dd95SBruce Richardson */ 53199a2dd95SBruce Richardson if (event_cb->active == 0) { 53299a2dd95SBruce Richardson TAILQ_REMOVE(&dev_event_cbs, event_cb, next); 53399a2dd95SBruce Richardson free(event_cb->dev_name); 53499a2dd95SBruce Richardson free(event_cb); 53599a2dd95SBruce Richardson ret++; 53699a2dd95SBruce Richardson } else { 53799a2dd95SBruce Richardson ret = -EAGAIN; 53899a2dd95SBruce Richardson break; 53999a2dd95SBruce Richardson } 54099a2dd95SBruce Richardson } 54199a2dd95SBruce Richardson 54299a2dd95SBruce Richardson /* this callback is not be registered */ 54399a2dd95SBruce Richardson if (ret == 0) 54499a2dd95SBruce Richardson ret = -ENOENT; 54599a2dd95SBruce Richardson 54699a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 54799a2dd95SBruce Richardson return ret; 54899a2dd95SBruce Richardson } 54999a2dd95SBruce Richardson 55099a2dd95SBruce Richardson void 55199a2dd95SBruce Richardson rte_dev_event_callback_process(const char *device_name, 55299a2dd95SBruce Richardson enum rte_dev_event_type event) 55399a2dd95SBruce Richardson { 55499a2dd95SBruce Richardson struct dev_event_callback *cb_lst; 55599a2dd95SBruce Richardson 55699a2dd95SBruce Richardson if (device_name == NULL) 55799a2dd95SBruce Richardson return; 55899a2dd95SBruce Richardson 55999a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 56099a2dd95SBruce Richardson 56199a2dd95SBruce Richardson TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) { 56299a2dd95SBruce Richardson if (cb_lst->dev_name) { 56399a2dd95SBruce Richardson if (strcmp(cb_lst->dev_name, device_name)) 56499a2dd95SBruce Richardson continue; 56599a2dd95SBruce Richardson } 56699a2dd95SBruce Richardson cb_lst->active = 1; 56799a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 56899a2dd95SBruce Richardson cb_lst->cb_fn(device_name, event, 56999a2dd95SBruce Richardson cb_lst->cb_arg); 57099a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 57199a2dd95SBruce Richardson cb_lst->active = 0; 57299a2dd95SBruce Richardson } 57399a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 57499a2dd95SBruce Richardson } 57599a2dd95SBruce Richardson 57699a2dd95SBruce Richardson int 57799a2dd95SBruce Richardson rte_dev_iterator_init(struct rte_dev_iterator *it, 57899a2dd95SBruce Richardson const char *dev_str) 57999a2dd95SBruce Richardson { 580fc382022SXueming Li struct rte_devargs devargs = { .bus = NULL }; 58199a2dd95SBruce Richardson struct rte_class *cls = NULL; 58299a2dd95SBruce Richardson struct rte_bus *bus = NULL; 58399a2dd95SBruce Richardson 58499a2dd95SBruce Richardson /* Having both bus_str and cls_str NULL is illegal, 58599a2dd95SBruce Richardson * marking this iterator as invalid unless 58699a2dd95SBruce Richardson * everything goes well. 58799a2dd95SBruce Richardson */ 58899a2dd95SBruce Richardson it->bus_str = NULL; 58999a2dd95SBruce Richardson it->cls_str = NULL; 59099a2dd95SBruce Richardson 59199a2dd95SBruce Richardson /* Setting data field implies no malloc in parsing. */ 59299a2dd95SBruce Richardson devargs.data = (void *)(intptr_t)dev_str; 59399a2dd95SBruce Richardson if (rte_devargs_layers_parse(&devargs, dev_str)) 59499a2dd95SBruce Richardson goto get_out; 59599a2dd95SBruce Richardson 59699a2dd95SBruce Richardson bus = devargs.bus; 59799a2dd95SBruce Richardson cls = devargs.cls; 59899a2dd95SBruce Richardson /* The string should have at least 59999a2dd95SBruce Richardson * one layer specified. 60099a2dd95SBruce Richardson */ 60199a2dd95SBruce Richardson if (bus == NULL && cls == NULL) { 60299948194SDavid Marchand RTE_LOG(DEBUG, EAL, "Either bus or class must be specified.\n"); 60399a2dd95SBruce Richardson rte_errno = EINVAL; 60499a2dd95SBruce Richardson goto get_out; 60599a2dd95SBruce Richardson } 60699a2dd95SBruce Richardson if (bus != NULL && bus->dev_iterate == NULL) { 60799948194SDavid Marchand RTE_LOG(DEBUG, EAL, "Bus %s not supported\n", bus->name); 60899a2dd95SBruce Richardson rte_errno = ENOTSUP; 60999a2dd95SBruce Richardson goto get_out; 61099a2dd95SBruce Richardson } 61199a2dd95SBruce Richardson if (cls != NULL && cls->dev_iterate == NULL) { 61299948194SDavid Marchand RTE_LOG(DEBUG, EAL, "Class %s not supported\n", cls->name); 61399a2dd95SBruce Richardson rte_errno = ENOTSUP; 61499a2dd95SBruce Richardson goto get_out; 61599a2dd95SBruce Richardson } 61699a2dd95SBruce Richardson it->bus_str = devargs.bus_str; 61799a2dd95SBruce Richardson it->cls_str = devargs.cls_str; 61899a2dd95SBruce Richardson it->dev_str = dev_str; 61999a2dd95SBruce Richardson it->bus = bus; 62099a2dd95SBruce Richardson it->cls = cls; 62199a2dd95SBruce Richardson it->device = NULL; 62299a2dd95SBruce Richardson it->class_device = NULL; 62399a2dd95SBruce Richardson get_out: 62499a2dd95SBruce Richardson return -rte_errno; 62599a2dd95SBruce Richardson } 62699a2dd95SBruce Richardson 62799a2dd95SBruce Richardson static char * 62899a2dd95SBruce Richardson dev_str_sane_copy(const char *str) 62999a2dd95SBruce Richardson { 63099a2dd95SBruce Richardson size_t end; 63199a2dd95SBruce Richardson char *copy; 63299a2dd95SBruce Richardson 63399a2dd95SBruce Richardson end = strcspn(str, ",/"); 63499a2dd95SBruce Richardson if (str[end] == ',') { 63599a2dd95SBruce Richardson copy = strdup(&str[end + 1]); 63699a2dd95SBruce Richardson } else { 63799a2dd95SBruce Richardson /* '/' or '\0' */ 63899a2dd95SBruce Richardson copy = strdup(""); 63999a2dd95SBruce Richardson } 64099a2dd95SBruce Richardson if (copy == NULL) { 64199a2dd95SBruce Richardson rte_errno = ENOMEM; 64299a2dd95SBruce Richardson } else { 64399a2dd95SBruce Richardson char *slash; 64499a2dd95SBruce Richardson 64599a2dd95SBruce Richardson slash = strchr(copy, '/'); 64699a2dd95SBruce Richardson if (slash != NULL) 64799a2dd95SBruce Richardson slash[0] = '\0'; 64899a2dd95SBruce Richardson } 64999a2dd95SBruce Richardson return copy; 65099a2dd95SBruce Richardson } 65199a2dd95SBruce Richardson 65299a2dd95SBruce Richardson static int 65399a2dd95SBruce Richardson class_next_dev_cmp(const struct rte_class *cls, 65499a2dd95SBruce Richardson const void *ctx) 65599a2dd95SBruce Richardson { 65699a2dd95SBruce Richardson struct rte_dev_iterator *it; 65799a2dd95SBruce Richardson const char *cls_str = NULL; 65899a2dd95SBruce Richardson void *dev; 65999a2dd95SBruce Richardson 66099a2dd95SBruce Richardson if (cls->dev_iterate == NULL) 66199a2dd95SBruce Richardson return 1; 66299a2dd95SBruce Richardson it = ITCTX(ctx); 66399a2dd95SBruce Richardson cls_str = CLSCTX(ctx); 66499a2dd95SBruce Richardson dev = it->class_device; 66599a2dd95SBruce Richardson /* it->cls_str != NULL means a class 66699a2dd95SBruce Richardson * was specified in the devstr. 66799a2dd95SBruce Richardson */ 66899a2dd95SBruce Richardson if (it->cls_str != NULL && cls != it->cls) 66999a2dd95SBruce Richardson return 1; 67099a2dd95SBruce Richardson /* If an error occurred previously, 67199a2dd95SBruce Richardson * no need to test further. 67299a2dd95SBruce Richardson */ 67399a2dd95SBruce Richardson if (rte_errno != 0) 67499a2dd95SBruce Richardson return -1; 67599a2dd95SBruce Richardson dev = cls->dev_iterate(dev, cls_str, it); 67699a2dd95SBruce Richardson it->class_device = dev; 67799a2dd95SBruce Richardson return dev == NULL; 67899a2dd95SBruce Richardson } 67999a2dd95SBruce Richardson 68099a2dd95SBruce Richardson static int 68199a2dd95SBruce Richardson bus_next_dev_cmp(const struct rte_bus *bus, 68299a2dd95SBruce Richardson const void *ctx) 68399a2dd95SBruce Richardson { 68499a2dd95SBruce Richardson struct rte_device *dev = NULL; 68599a2dd95SBruce Richardson struct rte_class *cls = NULL; 68699a2dd95SBruce Richardson struct rte_dev_iterator *it; 68799a2dd95SBruce Richardson const char *bus_str = NULL; 68899a2dd95SBruce Richardson 68999a2dd95SBruce Richardson if (bus->dev_iterate == NULL) 69099a2dd95SBruce Richardson return 1; 69199a2dd95SBruce Richardson it = ITCTX(ctx); 69299a2dd95SBruce Richardson bus_str = BUSCTX(ctx); 69399a2dd95SBruce Richardson dev = it->device; 69499a2dd95SBruce Richardson /* it->bus_str != NULL means a bus 69599a2dd95SBruce Richardson * was specified in the devstr. 69699a2dd95SBruce Richardson */ 69799a2dd95SBruce Richardson if (it->bus_str != NULL && bus != it->bus) 69899a2dd95SBruce Richardson return 1; 69999a2dd95SBruce Richardson /* If an error occurred previously, 70099a2dd95SBruce Richardson * no need to test further. 70199a2dd95SBruce Richardson */ 70299a2dd95SBruce Richardson if (rte_errno != 0) 70399a2dd95SBruce Richardson return -1; 70499a2dd95SBruce Richardson if (it->cls_str == NULL) { 70599a2dd95SBruce Richardson dev = bus->dev_iterate(dev, bus_str, it); 70699a2dd95SBruce Richardson goto end; 70799a2dd95SBruce Richardson } 70899a2dd95SBruce Richardson /* cls_str != NULL */ 70999a2dd95SBruce Richardson if (dev == NULL) { 71099a2dd95SBruce Richardson next_dev_on_bus: 71199a2dd95SBruce Richardson dev = bus->dev_iterate(dev, bus_str, it); 71299a2dd95SBruce Richardson it->device = dev; 71399a2dd95SBruce Richardson } 71499a2dd95SBruce Richardson if (dev == NULL) 71599a2dd95SBruce Richardson return 1; 71699a2dd95SBruce Richardson if (it->cls != NULL) 71799a2dd95SBruce Richardson cls = TAILQ_PREV(it->cls, rte_class_list, next); 71899a2dd95SBruce Richardson cls = rte_class_find(cls, class_next_dev_cmp, ctx); 71999a2dd95SBruce Richardson if (cls != NULL) { 72099a2dd95SBruce Richardson it->cls = cls; 72199a2dd95SBruce Richardson goto end; 72299a2dd95SBruce Richardson } 72399a2dd95SBruce Richardson goto next_dev_on_bus; 72499a2dd95SBruce Richardson end: 72599a2dd95SBruce Richardson it->device = dev; 72699a2dd95SBruce Richardson return dev == NULL; 72799a2dd95SBruce Richardson } 72899a2dd95SBruce Richardson struct rte_device * 72999a2dd95SBruce Richardson rte_dev_iterator_next(struct rte_dev_iterator *it) 73099a2dd95SBruce Richardson { 73199a2dd95SBruce Richardson struct rte_bus *bus = NULL; 73299a2dd95SBruce Richardson int old_errno = rte_errno; 73399a2dd95SBruce Richardson char *bus_str = NULL; 73499a2dd95SBruce Richardson char *cls_str = NULL; 73599a2dd95SBruce Richardson 73699a2dd95SBruce Richardson rte_errno = 0; 73799a2dd95SBruce Richardson if (it->bus_str == NULL && it->cls_str == NULL) { 73899a2dd95SBruce Richardson /* Invalid iterator. */ 73999a2dd95SBruce Richardson rte_errno = EINVAL; 74099a2dd95SBruce Richardson return NULL; 74199a2dd95SBruce Richardson } 74299a2dd95SBruce Richardson if (it->bus != NULL) 74399a2dd95SBruce Richardson bus = TAILQ_PREV(it->bus, rte_bus_list, next); 74499a2dd95SBruce Richardson if (it->bus_str != NULL) { 74599a2dd95SBruce Richardson bus_str = dev_str_sane_copy(it->bus_str); 74699a2dd95SBruce Richardson if (bus_str == NULL) 74799a2dd95SBruce Richardson goto out; 74899a2dd95SBruce Richardson } 74999a2dd95SBruce Richardson if (it->cls_str != NULL) { 75099a2dd95SBruce Richardson cls_str = dev_str_sane_copy(it->cls_str); 75199a2dd95SBruce Richardson if (cls_str == NULL) 75299a2dd95SBruce Richardson goto out; 75399a2dd95SBruce Richardson } 75499a2dd95SBruce Richardson while ((bus = rte_bus_find(bus, bus_next_dev_cmp, 75599a2dd95SBruce Richardson CTX(it, bus_str, cls_str)))) { 75699a2dd95SBruce Richardson if (it->device != NULL) { 75799a2dd95SBruce Richardson it->bus = bus; 75899a2dd95SBruce Richardson goto out; 75999a2dd95SBruce Richardson } 76099a2dd95SBruce Richardson if (it->bus_str != NULL || 76199a2dd95SBruce Richardson rte_errno != 0) 76299a2dd95SBruce Richardson break; 76399a2dd95SBruce Richardson } 76499a2dd95SBruce Richardson if (rte_errno == 0) 76599a2dd95SBruce Richardson rte_errno = old_errno; 76699a2dd95SBruce Richardson out: 76799a2dd95SBruce Richardson free(bus_str); 76899a2dd95SBruce Richardson free(cls_str); 76999a2dd95SBruce Richardson return it->device; 77099a2dd95SBruce Richardson } 77199a2dd95SBruce Richardson 77299a2dd95SBruce Richardson int 77399a2dd95SBruce Richardson rte_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, 77499a2dd95SBruce Richardson size_t len) 77599a2dd95SBruce Richardson { 77699a2dd95SBruce Richardson if (dev->bus->dma_map == NULL || len == 0) { 77799a2dd95SBruce Richardson rte_errno = ENOTSUP; 77899a2dd95SBruce Richardson return -1; 77999a2dd95SBruce Richardson } 78099a2dd95SBruce Richardson /* Memory must be registered through rte_extmem_* APIs */ 78199a2dd95SBruce Richardson if (rte_mem_virt2memseg_list(addr) == NULL) { 78299a2dd95SBruce Richardson rte_errno = EINVAL; 78399a2dd95SBruce Richardson return -1; 78499a2dd95SBruce Richardson } 78599a2dd95SBruce Richardson 78699a2dd95SBruce Richardson return dev->bus->dma_map(dev, addr, iova, len); 78799a2dd95SBruce Richardson } 78899a2dd95SBruce Richardson 78999a2dd95SBruce Richardson int 79099a2dd95SBruce Richardson rte_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, 79199a2dd95SBruce Richardson size_t len) 79299a2dd95SBruce Richardson { 79399a2dd95SBruce Richardson if (dev->bus->dma_unmap == NULL || len == 0) { 79499a2dd95SBruce Richardson rte_errno = ENOTSUP; 79599a2dd95SBruce Richardson return -1; 79699a2dd95SBruce Richardson } 79799a2dd95SBruce Richardson /* Memory must be registered through rte_extmem_* APIs */ 79899a2dd95SBruce Richardson if (rte_mem_virt2memseg_list(addr) == NULL) { 79999a2dd95SBruce Richardson rte_errno = EINVAL; 80099a2dd95SBruce Richardson return -1; 80199a2dd95SBruce Richardson } 80299a2dd95SBruce Richardson 80399a2dd95SBruce Richardson return dev->bus->dma_unmap(dev, addr, iova, len); 80499a2dd95SBruce Richardson } 805