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> 131acb7f54SDavid Marchand #include <dev_driver.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 2397bbdba3SDavid Marchand const char * 2497bbdba3SDavid Marchand rte_driver_name(const struct rte_driver *driver) 2597bbdba3SDavid Marchand { 2697bbdba3SDavid Marchand return driver->name; 2797bbdba3SDavid Marchand } 2897bbdba3SDavid Marchand 29ec5ecd7eSDavid Marchand const struct rte_bus * 30ec5ecd7eSDavid Marchand rte_dev_bus(const struct rte_device *dev) 31ec5ecd7eSDavid Marchand { 32ec5ecd7eSDavid Marchand return dev->bus; 33ec5ecd7eSDavid Marchand } 34ec5ecd7eSDavid Marchand 355b569f2eSDavid Marchand const char * 365b569f2eSDavid Marchand rte_dev_bus_info(const struct rte_device *dev) 375b569f2eSDavid Marchand { 385b569f2eSDavid Marchand return dev->bus_info; 395b569f2eSDavid Marchand } 405b569f2eSDavid Marchand 41ec5ecd7eSDavid Marchand const struct rte_devargs * 42ec5ecd7eSDavid Marchand rte_dev_devargs(const struct rte_device *dev) 43ec5ecd7eSDavid Marchand { 44ec5ecd7eSDavid Marchand return dev->devargs; 45ec5ecd7eSDavid Marchand } 46ec5ecd7eSDavid Marchand 47ec5ecd7eSDavid Marchand const struct rte_driver * 48ec5ecd7eSDavid Marchand rte_dev_driver(const struct rte_device *dev) 49ec5ecd7eSDavid Marchand { 50ec5ecd7eSDavid Marchand return dev->driver; 51ec5ecd7eSDavid Marchand } 52ec5ecd7eSDavid Marchand 53ec5ecd7eSDavid Marchand const char * 54ec5ecd7eSDavid Marchand rte_dev_name(const struct rte_device *dev) 55ec5ecd7eSDavid Marchand { 56ec5ecd7eSDavid Marchand return dev->name; 57ec5ecd7eSDavid Marchand } 58ec5ecd7eSDavid Marchand 59ec5ecd7eSDavid Marchand int 60ec5ecd7eSDavid Marchand rte_dev_numa_node(const struct rte_device *dev) 61ec5ecd7eSDavid Marchand { 62ec5ecd7eSDavid Marchand return dev->numa_node; 63ec5ecd7eSDavid Marchand } 64ec5ecd7eSDavid Marchand 6599a2dd95SBruce Richardson /** 6699a2dd95SBruce Richardson * The device event callback description. 6799a2dd95SBruce Richardson * 6899a2dd95SBruce Richardson * It contains callback address to be registered by user application, 6999a2dd95SBruce Richardson * the pointer to the parameters for callback, and the device name. 7099a2dd95SBruce Richardson */ 7199a2dd95SBruce Richardson struct dev_event_callback { 7299a2dd95SBruce Richardson TAILQ_ENTRY(dev_event_callback) next; /**< Callbacks list */ 7399a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn; /**< Callback address */ 7499a2dd95SBruce Richardson void *cb_arg; /**< Callback parameter */ 7599a2dd95SBruce Richardson char *dev_name; /**< Callback device name, NULL is for all device */ 7699a2dd95SBruce Richardson uint32_t active; /**< Callback is executing */ 7799a2dd95SBruce Richardson }; 7899a2dd95SBruce Richardson 7999a2dd95SBruce Richardson /** @internal Structure to keep track of registered callbacks */ 8099a2dd95SBruce Richardson TAILQ_HEAD(dev_event_cb_list, dev_event_callback); 8199a2dd95SBruce Richardson 8299a2dd95SBruce Richardson /* The device event callback list for all registered callbacks. */ 8399a2dd95SBruce Richardson static struct dev_event_cb_list dev_event_cbs; 8499a2dd95SBruce Richardson 8599a2dd95SBruce Richardson /* spinlock for device callbacks */ 8699a2dd95SBruce Richardson static rte_spinlock_t dev_event_lock = RTE_SPINLOCK_INITIALIZER; 8799a2dd95SBruce Richardson 8899a2dd95SBruce Richardson struct dev_next_ctx { 8999a2dd95SBruce Richardson struct rte_dev_iterator *it; 9099a2dd95SBruce Richardson const char *bus_str; 9199a2dd95SBruce Richardson const char *cls_str; 9299a2dd95SBruce Richardson }; 9399a2dd95SBruce Richardson 9499a2dd95SBruce Richardson #define CTX(it, bus_str, cls_str) \ 9599a2dd95SBruce Richardson (&(const struct dev_next_ctx){ \ 9699a2dd95SBruce Richardson .it = it, \ 9799a2dd95SBruce Richardson .bus_str = bus_str, \ 9899a2dd95SBruce Richardson .cls_str = cls_str, \ 9999a2dd95SBruce Richardson }) 10099a2dd95SBruce Richardson 10199a2dd95SBruce Richardson #define ITCTX(ptr) \ 10299a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->it) 10399a2dd95SBruce Richardson 10499a2dd95SBruce Richardson #define BUSCTX(ptr) \ 10599a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->bus_str) 10699a2dd95SBruce Richardson 10799a2dd95SBruce Richardson #define CLSCTX(ptr) \ 10899a2dd95SBruce Richardson (((struct dev_next_ctx *)(intptr_t)ptr)->cls_str) 10999a2dd95SBruce Richardson 11099a2dd95SBruce Richardson static int cmp_dev_name(const struct rte_device *dev, const void *_name) 11199a2dd95SBruce Richardson { 11299a2dd95SBruce Richardson const char *name = _name; 11399a2dd95SBruce Richardson 11499a2dd95SBruce Richardson return strcmp(dev->name, name); 11599a2dd95SBruce Richardson } 11699a2dd95SBruce Richardson 11799a2dd95SBruce Richardson int 11899a2dd95SBruce Richardson rte_dev_is_probed(const struct rte_device *dev) 11999a2dd95SBruce Richardson { 12099a2dd95SBruce Richardson /* The field driver should be set only when the probe is successful. */ 12199a2dd95SBruce Richardson return dev->driver != NULL; 12299a2dd95SBruce Richardson } 12399a2dd95SBruce Richardson 12499a2dd95SBruce Richardson /* helper function to build devargs, caller should free the memory */ 12599a2dd95SBruce Richardson static int 12699a2dd95SBruce Richardson build_devargs(const char *busname, const char *devname, 12799a2dd95SBruce Richardson const char *drvargs, char **devargs) 12899a2dd95SBruce Richardson { 12999a2dd95SBruce Richardson int length; 13099a2dd95SBruce Richardson 13199a2dd95SBruce Richardson length = snprintf(NULL, 0, "%s:%s,%s", busname, devname, drvargs); 13299a2dd95SBruce Richardson if (length < 0) 13399a2dd95SBruce Richardson return -EINVAL; 13499a2dd95SBruce Richardson 13599a2dd95SBruce Richardson *devargs = malloc(length + 1); 13699a2dd95SBruce Richardson if (*devargs == NULL) 13799a2dd95SBruce Richardson return -ENOMEM; 13899a2dd95SBruce Richardson 13999a2dd95SBruce Richardson length = snprintf(*devargs, length + 1, "%s:%s,%s", 14099a2dd95SBruce Richardson busname, devname, drvargs); 14199a2dd95SBruce Richardson if (length < 0) { 14299a2dd95SBruce Richardson free(*devargs); 14399a2dd95SBruce Richardson return -EINVAL; 14499a2dd95SBruce Richardson } 14599a2dd95SBruce Richardson 14699a2dd95SBruce Richardson return 0; 14799a2dd95SBruce Richardson } 14899a2dd95SBruce Richardson 14999a2dd95SBruce Richardson int 15099a2dd95SBruce Richardson rte_eal_hotplug_add(const char *busname, const char *devname, 15199a2dd95SBruce Richardson const char *drvargs) 15299a2dd95SBruce Richardson { 15399a2dd95SBruce Richardson 15499a2dd95SBruce Richardson char *devargs; 15599a2dd95SBruce Richardson int ret; 15699a2dd95SBruce Richardson 15799a2dd95SBruce Richardson ret = build_devargs(busname, devname, drvargs, &devargs); 15899a2dd95SBruce Richardson if (ret != 0) 15999a2dd95SBruce Richardson return ret; 16099a2dd95SBruce Richardson 16199a2dd95SBruce Richardson ret = rte_dev_probe(devargs); 16299a2dd95SBruce Richardson free(devargs); 16399a2dd95SBruce Richardson 16499a2dd95SBruce Richardson return ret; 16599a2dd95SBruce Richardson } 16699a2dd95SBruce Richardson 16799a2dd95SBruce Richardson /* probe device at local process. */ 16899a2dd95SBruce Richardson int 16999a2dd95SBruce Richardson local_dev_probe(const char *devargs, struct rte_device **new_dev) 17099a2dd95SBruce Richardson { 17199a2dd95SBruce Richardson struct rte_device *dev; 17299a2dd95SBruce Richardson struct rte_devargs *da; 17399a2dd95SBruce Richardson int ret; 17499a2dd95SBruce Richardson 17599a2dd95SBruce Richardson *new_dev = NULL; 17699a2dd95SBruce Richardson da = calloc(1, sizeof(*da)); 17799a2dd95SBruce Richardson if (da == NULL) 17899a2dd95SBruce Richardson return -ENOMEM; 17999a2dd95SBruce Richardson 18099a2dd95SBruce Richardson ret = rte_devargs_parse(da, devargs); 18199a2dd95SBruce Richardson if (ret) 18299a2dd95SBruce Richardson goto err_devarg; 18399a2dd95SBruce Richardson 18499a2dd95SBruce Richardson if (da->bus->plug == NULL) { 185ae67895bSDavid Marchand EAL_LOG(ERR, "Function plug not supported by bus (%s)", 18699a2dd95SBruce Richardson da->bus->name); 18799a2dd95SBruce Richardson ret = -ENOTSUP; 18899a2dd95SBruce Richardson goto err_devarg; 18999a2dd95SBruce Richardson } 19099a2dd95SBruce Richardson 19199a2dd95SBruce Richardson ret = rte_devargs_insert(&da); 19299a2dd95SBruce Richardson if (ret) 19399a2dd95SBruce Richardson goto err_devarg; 19499a2dd95SBruce Richardson 19599a2dd95SBruce Richardson /* the rte_devargs will be referenced in the matching rte_device */ 19699a2dd95SBruce Richardson ret = da->bus->scan(); 19799a2dd95SBruce Richardson if (ret) 19899a2dd95SBruce Richardson goto err_devarg; 19999a2dd95SBruce Richardson 20099a2dd95SBruce Richardson dev = da->bus->find_device(NULL, cmp_dev_name, da->name); 20199a2dd95SBruce Richardson if (dev == NULL) { 202ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot find device (%s)", 20399a2dd95SBruce Richardson da->name); 20499a2dd95SBruce Richardson ret = -ENODEV; 20599a2dd95SBruce Richardson goto err_devarg; 20699a2dd95SBruce Richardson } 20799a2dd95SBruce Richardson /* Since there is a matching device, it is now its responsibility 20899a2dd95SBruce Richardson * to manage the devargs we've just inserted. From this point 20999a2dd95SBruce Richardson * those devargs shouldn't be removed manually anymore. 21099a2dd95SBruce Richardson */ 21199a2dd95SBruce Richardson 21299a2dd95SBruce Richardson ret = dev->bus->plug(dev); 21399a2dd95SBruce Richardson if (ret > 0) 21499a2dd95SBruce Richardson ret = -ENOTSUP; 21599a2dd95SBruce Richardson 21699a2dd95SBruce Richardson if (ret && !rte_dev_is_probed(dev)) { /* if hasn't ever succeeded */ 217ae67895bSDavid Marchand EAL_LOG(ERR, "Driver cannot attach the device (%s)", 21899a2dd95SBruce Richardson dev->name); 21999a2dd95SBruce Richardson return ret; 22099a2dd95SBruce Richardson } 22199a2dd95SBruce Richardson 22299a2dd95SBruce Richardson *new_dev = dev; 22399a2dd95SBruce Richardson return ret; 22499a2dd95SBruce Richardson 22599a2dd95SBruce Richardson err_devarg: 22626d734b5SDavid Marchand if (rte_devargs_remove(da) != 0) { 22799a2dd95SBruce Richardson rte_devargs_reset(da); 22826d734b5SDavid Marchand free(da); 22926d734b5SDavid Marchand } 23099a2dd95SBruce Richardson return ret; 23199a2dd95SBruce Richardson } 23299a2dd95SBruce Richardson 23399a2dd95SBruce Richardson int 23499a2dd95SBruce Richardson rte_dev_probe(const char *devargs) 23599a2dd95SBruce Richardson { 23699a2dd95SBruce Richardson struct eal_dev_mp_req req; 23799a2dd95SBruce Richardson struct rte_device *dev; 23899a2dd95SBruce Richardson int ret; 23999a2dd95SBruce Richardson 24099a2dd95SBruce Richardson memset(&req, 0, sizeof(req)); 24199a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_ATTACH; 24299a2dd95SBruce Richardson strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 24399a2dd95SBruce Richardson 24499a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 24599a2dd95SBruce Richardson /** 24699a2dd95SBruce Richardson * If in secondary process, just send IPC request to 24799a2dd95SBruce Richardson * primary process. 24899a2dd95SBruce Richardson */ 24999a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_primary(&req); 25099a2dd95SBruce Richardson if (ret != 0) { 251ae67895bSDavid Marchand EAL_LOG(ERR, 252ae67895bSDavid Marchand "Failed to send hotplug request to primary"); 25399a2dd95SBruce Richardson return -ENOMSG; 25499a2dd95SBruce Richardson } 25599a2dd95SBruce Richardson if (req.result != 0) 256ae67895bSDavid Marchand EAL_LOG(ERR, 257ae67895bSDavid Marchand "Failed to hotplug add device"); 25899a2dd95SBruce Richardson return req.result; 25999a2dd95SBruce Richardson } 26099a2dd95SBruce Richardson 26199a2dd95SBruce Richardson /* attach a shared device from primary start from here: */ 26299a2dd95SBruce Richardson 26399a2dd95SBruce Richardson /* primary attach the new device itself. */ 26499a2dd95SBruce Richardson ret = local_dev_probe(devargs, &dev); 26599a2dd95SBruce Richardson 26699a2dd95SBruce Richardson if (ret != 0) { 267ae67895bSDavid Marchand EAL_LOG(ERR, 268ae67895bSDavid Marchand "Failed to attach device on primary process"); 26999a2dd95SBruce Richardson 27099a2dd95SBruce Richardson /** 27199a2dd95SBruce Richardson * it is possible that secondary process failed to attached a 27299a2dd95SBruce Richardson * device that primary process have during initialization, 27399a2dd95SBruce Richardson * so for -EEXIST case, we still need to sync with secondary 27499a2dd95SBruce Richardson * process. 27599a2dd95SBruce Richardson */ 27699a2dd95SBruce Richardson if (ret != -EEXIST) 27799a2dd95SBruce Richardson return ret; 27899a2dd95SBruce Richardson } 27999a2dd95SBruce Richardson 28099a2dd95SBruce Richardson /* primary send attach sync request to secondary. */ 28199a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_secondary(&req); 28299a2dd95SBruce Richardson 28399a2dd95SBruce Richardson /* if any communication error, we need to rollback. */ 28499a2dd95SBruce Richardson if (ret != 0) { 285ae67895bSDavid Marchand EAL_LOG(ERR, 286ae67895bSDavid Marchand "Failed to send hotplug add request to secondary"); 28799a2dd95SBruce Richardson ret = -ENOMSG; 28899a2dd95SBruce Richardson goto rollback; 28999a2dd95SBruce Richardson } 29099a2dd95SBruce Richardson 29199a2dd95SBruce Richardson /** 29299a2dd95SBruce Richardson * if any secondary failed to attach, we need to consider if rollback 29399a2dd95SBruce Richardson * is necessary. 29499a2dd95SBruce Richardson */ 29599a2dd95SBruce Richardson if (req.result != 0) { 296ae67895bSDavid Marchand EAL_LOG(ERR, 297ae67895bSDavid Marchand "Failed to attach device on secondary process"); 29899a2dd95SBruce Richardson ret = req.result; 29999a2dd95SBruce Richardson 30099a2dd95SBruce Richardson /* for -EEXIST, we don't need to rollback. */ 30199a2dd95SBruce Richardson if (ret == -EEXIST) 30299a2dd95SBruce Richardson return ret; 30399a2dd95SBruce Richardson goto rollback; 30499a2dd95SBruce Richardson } 30599a2dd95SBruce Richardson 30699a2dd95SBruce Richardson return 0; 30799a2dd95SBruce Richardson 30899a2dd95SBruce Richardson rollback: 30999a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_ATTACH_ROLLBACK; 31099a2dd95SBruce Richardson 31199a2dd95SBruce Richardson /* primary send rollback request to secondary. */ 31299a2dd95SBruce Richardson if (eal_dev_hotplug_request_to_secondary(&req) != 0) 313ae67895bSDavid Marchand EAL_LOG(WARNING, 31499a2dd95SBruce Richardson "Failed to rollback device attach on secondary." 315ae67895bSDavid Marchand "Devices in secondary may not sync with primary"); 31699a2dd95SBruce Richardson 31799a2dd95SBruce Richardson /* primary rollback itself. */ 31899a2dd95SBruce Richardson if (local_dev_remove(dev) != 0) 319ae67895bSDavid Marchand EAL_LOG(WARNING, 32099a2dd95SBruce Richardson "Failed to rollback device attach on primary." 321ae67895bSDavid Marchand "Devices in secondary may not sync with primary"); 32299a2dd95SBruce Richardson 32399a2dd95SBruce Richardson return ret; 32499a2dd95SBruce Richardson } 32599a2dd95SBruce Richardson 32699a2dd95SBruce Richardson int 32799a2dd95SBruce Richardson rte_eal_hotplug_remove(const char *busname, const char *devname) 32899a2dd95SBruce Richardson { 32999a2dd95SBruce Richardson struct rte_device *dev; 33099a2dd95SBruce Richardson struct rte_bus *bus; 33199a2dd95SBruce Richardson 33299a2dd95SBruce Richardson bus = rte_bus_find_by_name(busname); 33399a2dd95SBruce Richardson if (bus == NULL) { 334ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot find bus (%s)", busname); 33599a2dd95SBruce Richardson return -ENOENT; 33699a2dd95SBruce Richardson } 33799a2dd95SBruce Richardson 33899a2dd95SBruce Richardson dev = bus->find_device(NULL, cmp_dev_name, devname); 33999a2dd95SBruce Richardson if (dev == NULL) { 340ae67895bSDavid Marchand EAL_LOG(ERR, "Cannot find plugged device (%s)", devname); 34199a2dd95SBruce Richardson return -EINVAL; 34299a2dd95SBruce Richardson } 34399a2dd95SBruce Richardson 34499a2dd95SBruce Richardson return rte_dev_remove(dev); 34599a2dd95SBruce Richardson } 34699a2dd95SBruce Richardson 34799a2dd95SBruce Richardson /* remove device at local process. */ 34899a2dd95SBruce Richardson int 34999a2dd95SBruce Richardson local_dev_remove(struct rte_device *dev) 35099a2dd95SBruce Richardson { 35199a2dd95SBruce Richardson int ret; 35299a2dd95SBruce Richardson 35399a2dd95SBruce Richardson if (dev->bus->unplug == NULL) { 354ae67895bSDavid Marchand EAL_LOG(ERR, "Function unplug not supported by bus (%s)", 35599a2dd95SBruce Richardson dev->bus->name); 35699a2dd95SBruce Richardson return -ENOTSUP; 35799a2dd95SBruce Richardson } 35899a2dd95SBruce Richardson 35999a2dd95SBruce Richardson ret = dev->bus->unplug(dev); 36099a2dd95SBruce Richardson if (ret) { 361ae67895bSDavid Marchand EAL_LOG(ERR, "Driver cannot detach the device (%s)", 36299a2dd95SBruce Richardson dev->name); 36399a2dd95SBruce Richardson return (ret < 0) ? ret : -ENOENT; 36499a2dd95SBruce Richardson } 36599a2dd95SBruce Richardson 36699a2dd95SBruce Richardson return 0; 36799a2dd95SBruce Richardson } 36899a2dd95SBruce Richardson 36999a2dd95SBruce Richardson int 37099a2dd95SBruce Richardson rte_dev_remove(struct rte_device *dev) 37199a2dd95SBruce Richardson { 37299a2dd95SBruce Richardson struct eal_dev_mp_req req; 37399a2dd95SBruce Richardson char *devargs; 37499a2dd95SBruce Richardson int ret; 37599a2dd95SBruce Richardson 37699a2dd95SBruce Richardson if (!rte_dev_is_probed(dev)) { 377ae67895bSDavid Marchand EAL_LOG(ERR, "Device is not probed"); 37899a2dd95SBruce Richardson return -ENOENT; 37999a2dd95SBruce Richardson } 38099a2dd95SBruce Richardson 38199a2dd95SBruce Richardson ret = build_devargs(dev->bus->name, dev->name, "", &devargs); 38299a2dd95SBruce Richardson if (ret != 0) 38399a2dd95SBruce Richardson return ret; 38499a2dd95SBruce Richardson 38599a2dd95SBruce Richardson memset(&req, 0, sizeof(req)); 38699a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_DETACH; 38799a2dd95SBruce Richardson strlcpy(req.devargs, devargs, EAL_DEV_MP_DEV_ARGS_MAX_LEN); 38899a2dd95SBruce Richardson free(devargs); 38999a2dd95SBruce Richardson 39099a2dd95SBruce Richardson if (rte_eal_process_type() != RTE_PROC_PRIMARY) { 39199a2dd95SBruce Richardson /** 39299a2dd95SBruce Richardson * If in secondary process, just send IPC request to 39399a2dd95SBruce Richardson * primary process. 39499a2dd95SBruce Richardson */ 39599a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_primary(&req); 39699a2dd95SBruce Richardson if (ret != 0) { 397ae67895bSDavid Marchand EAL_LOG(ERR, 398ae67895bSDavid Marchand "Failed to send hotplug request to primary"); 39999a2dd95SBruce Richardson return -ENOMSG; 40099a2dd95SBruce Richardson } 40199a2dd95SBruce Richardson if (req.result != 0) 402ae67895bSDavid Marchand EAL_LOG(ERR, 403ae67895bSDavid Marchand "Failed to hotplug remove device"); 40499a2dd95SBruce Richardson return req.result; 40599a2dd95SBruce Richardson } 40699a2dd95SBruce Richardson 40799a2dd95SBruce Richardson /* detach a device from primary start from here: */ 40899a2dd95SBruce Richardson 40999a2dd95SBruce Richardson /* primary send detach sync request to secondary */ 41099a2dd95SBruce Richardson ret = eal_dev_hotplug_request_to_secondary(&req); 41199a2dd95SBruce Richardson 41299a2dd95SBruce Richardson /** 41399a2dd95SBruce Richardson * if communication error, we need to rollback, because it is possible 41499a2dd95SBruce Richardson * part of the secondary processes still detached it successfully. 41599a2dd95SBruce Richardson */ 41699a2dd95SBruce Richardson if (ret != 0) { 417ae67895bSDavid Marchand EAL_LOG(ERR, 418ae67895bSDavid Marchand "Failed to send device detach request to secondary"); 41999a2dd95SBruce Richardson ret = -ENOMSG; 42099a2dd95SBruce Richardson goto rollback; 42199a2dd95SBruce Richardson } 42299a2dd95SBruce Richardson 42399a2dd95SBruce Richardson /** 42499a2dd95SBruce Richardson * if any secondary failed to detach, we need to consider if rollback 42599a2dd95SBruce Richardson * is necessary. 42699a2dd95SBruce Richardson */ 42799a2dd95SBruce Richardson if (req.result != 0) { 428ae67895bSDavid Marchand EAL_LOG(ERR, 429ae67895bSDavid Marchand "Failed to detach device on secondary process"); 43099a2dd95SBruce Richardson ret = req.result; 43199a2dd95SBruce Richardson /** 43299a2dd95SBruce Richardson * if -ENOENT, we don't need to rollback, since devices is 43399a2dd95SBruce Richardson * already detached on secondary process. 43499a2dd95SBruce Richardson */ 43599a2dd95SBruce Richardson if (ret != -ENOENT) 43699a2dd95SBruce Richardson goto rollback; 43799a2dd95SBruce Richardson } 43899a2dd95SBruce Richardson 43999a2dd95SBruce Richardson /* primary detach the device itself. */ 44099a2dd95SBruce Richardson ret = local_dev_remove(dev); 44199a2dd95SBruce Richardson 44299a2dd95SBruce Richardson /* if primary failed, still need to consider if rollback is necessary */ 44399a2dd95SBruce Richardson if (ret != 0) { 444ae67895bSDavid Marchand EAL_LOG(ERR, 445ae67895bSDavid Marchand "Failed to detach device on primary process"); 44699a2dd95SBruce Richardson /* if -ENOENT, we don't need to rollback */ 44799a2dd95SBruce Richardson if (ret == -ENOENT) 44899a2dd95SBruce Richardson return ret; 44999a2dd95SBruce Richardson goto rollback; 45099a2dd95SBruce Richardson } 45199a2dd95SBruce Richardson 45299a2dd95SBruce Richardson return 0; 45399a2dd95SBruce Richardson 45499a2dd95SBruce Richardson rollback: 45599a2dd95SBruce Richardson req.t = EAL_DEV_REQ_TYPE_DETACH_ROLLBACK; 45699a2dd95SBruce Richardson 45799a2dd95SBruce Richardson /* primary send rollback request to secondary. */ 45899a2dd95SBruce Richardson if (eal_dev_hotplug_request_to_secondary(&req) != 0) 459ae67895bSDavid Marchand EAL_LOG(WARNING, 46099a2dd95SBruce Richardson "Failed to rollback device detach on secondary." 461ae67895bSDavid Marchand "Devices in secondary may not sync with primary"); 46299a2dd95SBruce Richardson 46399a2dd95SBruce Richardson return ret; 46499a2dd95SBruce Richardson } 46599a2dd95SBruce Richardson 46699a2dd95SBruce Richardson int 46799a2dd95SBruce Richardson rte_dev_event_callback_register(const char *device_name, 46899a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn, 46999a2dd95SBruce Richardson void *cb_arg) 47099a2dd95SBruce Richardson { 47199a2dd95SBruce Richardson struct dev_event_callback *event_cb; 47299a2dd95SBruce Richardson int ret; 47399a2dd95SBruce Richardson 47499a2dd95SBruce Richardson if (!cb_fn) 47599a2dd95SBruce Richardson return -EINVAL; 47699a2dd95SBruce Richardson 47799a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 47899a2dd95SBruce Richardson 47999a2dd95SBruce Richardson if (TAILQ_EMPTY(&dev_event_cbs)) 48099a2dd95SBruce Richardson TAILQ_INIT(&dev_event_cbs); 48199a2dd95SBruce Richardson 48299a2dd95SBruce Richardson TAILQ_FOREACH(event_cb, &dev_event_cbs, next) { 48399a2dd95SBruce Richardson if (event_cb->cb_fn == cb_fn && event_cb->cb_arg == cb_arg) { 48499a2dd95SBruce Richardson if (device_name == NULL && event_cb->dev_name == NULL) 48599a2dd95SBruce Richardson break; 48699a2dd95SBruce Richardson if (device_name == NULL || event_cb->dev_name == NULL) 48799a2dd95SBruce Richardson continue; 48899a2dd95SBruce Richardson if (!strcmp(event_cb->dev_name, device_name)) 48999a2dd95SBruce Richardson break; 49099a2dd95SBruce Richardson } 49199a2dd95SBruce Richardson } 49299a2dd95SBruce Richardson 49399a2dd95SBruce Richardson /* create a new callback. */ 49499a2dd95SBruce Richardson if (event_cb == NULL) { 49599a2dd95SBruce Richardson event_cb = malloc(sizeof(struct dev_event_callback)); 49699a2dd95SBruce Richardson if (event_cb != NULL) { 49799a2dd95SBruce Richardson event_cb->cb_fn = cb_fn; 49899a2dd95SBruce Richardson event_cb->cb_arg = cb_arg; 49999a2dd95SBruce Richardson event_cb->active = 0; 50099a2dd95SBruce Richardson if (!device_name) { 50199a2dd95SBruce Richardson event_cb->dev_name = NULL; 50299a2dd95SBruce Richardson } else { 50399a2dd95SBruce Richardson event_cb->dev_name = strdup(device_name); 50499a2dd95SBruce Richardson if (event_cb->dev_name == NULL) { 50599a2dd95SBruce Richardson ret = -ENOMEM; 50699a2dd95SBruce Richardson goto error; 50799a2dd95SBruce Richardson } 50899a2dd95SBruce Richardson } 50999a2dd95SBruce Richardson TAILQ_INSERT_TAIL(&dev_event_cbs, event_cb, next); 51099a2dd95SBruce Richardson } else { 511ae67895bSDavid Marchand EAL_LOG(ERR, 51299a2dd95SBruce Richardson "Failed to allocate memory for device " 51399a2dd95SBruce Richardson "event callback."); 51499a2dd95SBruce Richardson ret = -ENOMEM; 51599a2dd95SBruce Richardson goto error; 51699a2dd95SBruce Richardson } 51799a2dd95SBruce Richardson } else { 518ae67895bSDavid Marchand EAL_LOG(ERR, 51999a2dd95SBruce Richardson "The callback is already exist, no need " 520ae67895bSDavid Marchand "to register again."); 52199a2dd95SBruce Richardson event_cb = NULL; 52299a2dd95SBruce Richardson ret = -EEXIST; 52399a2dd95SBruce Richardson goto error; 52499a2dd95SBruce Richardson } 52599a2dd95SBruce Richardson 52699a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 52799a2dd95SBruce Richardson return 0; 52899a2dd95SBruce Richardson error: 52999a2dd95SBruce Richardson free(event_cb); 53099a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 53199a2dd95SBruce Richardson return ret; 53299a2dd95SBruce Richardson } 53399a2dd95SBruce Richardson 53499a2dd95SBruce Richardson int 53599a2dd95SBruce Richardson rte_dev_event_callback_unregister(const char *device_name, 53699a2dd95SBruce Richardson rte_dev_event_cb_fn cb_fn, 53799a2dd95SBruce Richardson void *cb_arg) 53899a2dd95SBruce Richardson { 53999a2dd95SBruce Richardson int ret = 0; 54099a2dd95SBruce Richardson struct dev_event_callback *event_cb, *next; 54199a2dd95SBruce Richardson 54299a2dd95SBruce Richardson if (!cb_fn) 54399a2dd95SBruce Richardson return -EINVAL; 54499a2dd95SBruce Richardson 54599a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 54699a2dd95SBruce Richardson /*walk through the callbacks and remove all that match. */ 54799a2dd95SBruce Richardson for (event_cb = TAILQ_FIRST(&dev_event_cbs); event_cb != NULL; 54899a2dd95SBruce Richardson event_cb = next) { 54999a2dd95SBruce Richardson 55099a2dd95SBruce Richardson next = TAILQ_NEXT(event_cb, next); 55199a2dd95SBruce Richardson 55299a2dd95SBruce Richardson if (device_name != NULL && event_cb->dev_name != NULL) { 553*66fd2cc2SMalcolm Bumgardner if (strcmp(event_cb->dev_name, device_name)) 55499a2dd95SBruce Richardson continue; 55599a2dd95SBruce Richardson } else if (device_name != NULL) { 55699a2dd95SBruce Richardson continue; 55799a2dd95SBruce Richardson } 55899a2dd95SBruce Richardson 559*66fd2cc2SMalcolm Bumgardner /* Remove only matching callback with arg */ 560*66fd2cc2SMalcolm Bumgardner if (event_cb->cb_fn != cb_fn || 561*66fd2cc2SMalcolm Bumgardner (cb_arg != (void *)-1 && event_cb->cb_arg != cb_arg)) 562*66fd2cc2SMalcolm Bumgardner continue; 563*66fd2cc2SMalcolm Bumgardner 56499a2dd95SBruce Richardson /* 56599a2dd95SBruce Richardson * if this callback is not executing right now, 56699a2dd95SBruce Richardson * then remove it. 56799a2dd95SBruce Richardson */ 56899a2dd95SBruce Richardson if (event_cb->active == 0) { 56999a2dd95SBruce Richardson TAILQ_REMOVE(&dev_event_cbs, event_cb, next); 57099a2dd95SBruce Richardson free(event_cb->dev_name); 57199a2dd95SBruce Richardson free(event_cb); 57299a2dd95SBruce Richardson ret++; 57399a2dd95SBruce Richardson } else { 57499a2dd95SBruce Richardson ret = -EAGAIN; 57599a2dd95SBruce Richardson break; 57699a2dd95SBruce Richardson } 57799a2dd95SBruce Richardson } 57899a2dd95SBruce Richardson 57999a2dd95SBruce Richardson /* this callback is not be registered */ 58099a2dd95SBruce Richardson if (ret == 0) 58199a2dd95SBruce Richardson ret = -ENOENT; 58299a2dd95SBruce Richardson 58399a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 58499a2dd95SBruce Richardson return ret; 58599a2dd95SBruce Richardson } 58699a2dd95SBruce Richardson 58799a2dd95SBruce Richardson void 58899a2dd95SBruce Richardson rte_dev_event_callback_process(const char *device_name, 58999a2dd95SBruce Richardson enum rte_dev_event_type event) 59099a2dd95SBruce Richardson { 59199a2dd95SBruce Richardson struct dev_event_callback *cb_lst; 59299a2dd95SBruce Richardson 59399a2dd95SBruce Richardson if (device_name == NULL) 59499a2dd95SBruce Richardson return; 59599a2dd95SBruce Richardson 59699a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 59799a2dd95SBruce Richardson 59899a2dd95SBruce Richardson TAILQ_FOREACH(cb_lst, &dev_event_cbs, next) { 59999a2dd95SBruce Richardson if (cb_lst->dev_name) { 60099a2dd95SBruce Richardson if (strcmp(cb_lst->dev_name, device_name)) 60199a2dd95SBruce Richardson continue; 60299a2dd95SBruce Richardson } 60399a2dd95SBruce Richardson cb_lst->active = 1; 60499a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 60599a2dd95SBruce Richardson cb_lst->cb_fn(device_name, event, 60699a2dd95SBruce Richardson cb_lst->cb_arg); 60799a2dd95SBruce Richardson rte_spinlock_lock(&dev_event_lock); 60899a2dd95SBruce Richardson cb_lst->active = 0; 60999a2dd95SBruce Richardson } 61099a2dd95SBruce Richardson rte_spinlock_unlock(&dev_event_lock); 61199a2dd95SBruce Richardson } 61299a2dd95SBruce Richardson 61399a2dd95SBruce Richardson int 61499a2dd95SBruce Richardson rte_dev_iterator_init(struct rte_dev_iterator *it, 61599a2dd95SBruce Richardson const char *dev_str) 61699a2dd95SBruce Richardson { 617fc382022SXueming Li struct rte_devargs devargs = { .bus = NULL }; 61899a2dd95SBruce Richardson struct rte_class *cls = NULL; 61999a2dd95SBruce Richardson struct rte_bus *bus = NULL; 62099a2dd95SBruce Richardson 62199a2dd95SBruce Richardson /* Having both bus_str and cls_str NULL is illegal, 62299a2dd95SBruce Richardson * marking this iterator as invalid unless 62399a2dd95SBruce Richardson * everything goes well. 62499a2dd95SBruce Richardson */ 62599a2dd95SBruce Richardson it->bus_str = NULL; 62699a2dd95SBruce Richardson it->cls_str = NULL; 62799a2dd95SBruce Richardson 62899a2dd95SBruce Richardson /* Setting data field implies no malloc in parsing. */ 62999a2dd95SBruce Richardson devargs.data = (void *)(intptr_t)dev_str; 63099a2dd95SBruce Richardson if (rte_devargs_layers_parse(&devargs, dev_str)) 63199a2dd95SBruce Richardson goto get_out; 63299a2dd95SBruce Richardson 63399a2dd95SBruce Richardson bus = devargs.bus; 63499a2dd95SBruce Richardson cls = devargs.cls; 63599a2dd95SBruce Richardson /* The string should have at least 63699a2dd95SBruce Richardson * one layer specified. 63799a2dd95SBruce Richardson */ 63899a2dd95SBruce Richardson if (bus == NULL && cls == NULL) { 639ae67895bSDavid Marchand EAL_LOG(DEBUG, "Either bus or class must be specified."); 64099a2dd95SBruce Richardson rte_errno = EINVAL; 64199a2dd95SBruce Richardson goto get_out; 64299a2dd95SBruce Richardson } 64399a2dd95SBruce Richardson if (bus != NULL && bus->dev_iterate == NULL) { 644ae67895bSDavid Marchand EAL_LOG(DEBUG, "Bus %s not supported", bus->name); 64599a2dd95SBruce Richardson rte_errno = ENOTSUP; 64699a2dd95SBruce Richardson goto get_out; 64799a2dd95SBruce Richardson } 64899a2dd95SBruce Richardson if (cls != NULL && cls->dev_iterate == NULL) { 649ae67895bSDavid Marchand EAL_LOG(DEBUG, "Class %s not supported", cls->name); 65099a2dd95SBruce Richardson rte_errno = ENOTSUP; 65199a2dd95SBruce Richardson goto get_out; 65299a2dd95SBruce Richardson } 65399a2dd95SBruce Richardson it->bus_str = devargs.bus_str; 65499a2dd95SBruce Richardson it->cls_str = devargs.cls_str; 65599a2dd95SBruce Richardson it->dev_str = dev_str; 65699a2dd95SBruce Richardson it->bus = bus; 65799a2dd95SBruce Richardson it->cls = cls; 65899a2dd95SBruce Richardson it->device = NULL; 65999a2dd95SBruce Richardson it->class_device = NULL; 66099a2dd95SBruce Richardson get_out: 66199a2dd95SBruce Richardson return -rte_errno; 66299a2dd95SBruce Richardson } 66399a2dd95SBruce Richardson 66499a2dd95SBruce Richardson static char * 66599a2dd95SBruce Richardson dev_str_sane_copy(const char *str) 66699a2dd95SBruce Richardson { 66799a2dd95SBruce Richardson size_t end; 66899a2dd95SBruce Richardson char *copy; 66999a2dd95SBruce Richardson 67099a2dd95SBruce Richardson end = strcspn(str, ",/"); 67199a2dd95SBruce Richardson if (str[end] == ',') { 67299a2dd95SBruce Richardson copy = strdup(&str[end + 1]); 67399a2dd95SBruce Richardson } else { 67499a2dd95SBruce Richardson /* '/' or '\0' */ 67599a2dd95SBruce Richardson copy = strdup(""); 67699a2dd95SBruce Richardson } 67799a2dd95SBruce Richardson if (copy == NULL) { 67899a2dd95SBruce Richardson rte_errno = ENOMEM; 67999a2dd95SBruce Richardson } else { 68099a2dd95SBruce Richardson char *slash; 68199a2dd95SBruce Richardson 68299a2dd95SBruce Richardson slash = strchr(copy, '/'); 68399a2dd95SBruce Richardson if (slash != NULL) 68499a2dd95SBruce Richardson slash[0] = '\0'; 68599a2dd95SBruce Richardson } 68699a2dd95SBruce Richardson return copy; 68799a2dd95SBruce Richardson } 68899a2dd95SBruce Richardson 68999a2dd95SBruce Richardson static int 69099a2dd95SBruce Richardson class_next_dev_cmp(const struct rte_class *cls, 69199a2dd95SBruce Richardson const void *ctx) 69299a2dd95SBruce Richardson { 69399a2dd95SBruce Richardson struct rte_dev_iterator *it; 69499a2dd95SBruce Richardson const char *cls_str = NULL; 69599a2dd95SBruce Richardson void *dev; 69699a2dd95SBruce Richardson 69799a2dd95SBruce Richardson if (cls->dev_iterate == NULL) 69899a2dd95SBruce Richardson return 1; 69999a2dd95SBruce Richardson it = ITCTX(ctx); 70099a2dd95SBruce Richardson cls_str = CLSCTX(ctx); 70199a2dd95SBruce Richardson dev = it->class_device; 70299a2dd95SBruce Richardson /* it->cls_str != NULL means a class 70399a2dd95SBruce Richardson * was specified in the devstr. 70499a2dd95SBruce Richardson */ 70599a2dd95SBruce Richardson if (it->cls_str != NULL && cls != it->cls) 70699a2dd95SBruce Richardson return 1; 70799a2dd95SBruce Richardson /* If an error occurred previously, 70899a2dd95SBruce Richardson * no need to test further. 70999a2dd95SBruce Richardson */ 71099a2dd95SBruce Richardson if (rte_errno != 0) 71199a2dd95SBruce Richardson return -1; 71299a2dd95SBruce Richardson dev = cls->dev_iterate(dev, cls_str, it); 71399a2dd95SBruce Richardson it->class_device = dev; 71499a2dd95SBruce Richardson return dev == NULL; 71599a2dd95SBruce Richardson } 71699a2dd95SBruce Richardson 71799a2dd95SBruce Richardson static int 71899a2dd95SBruce Richardson bus_next_dev_cmp(const struct rte_bus *bus, 71999a2dd95SBruce Richardson const void *ctx) 72099a2dd95SBruce Richardson { 72199a2dd95SBruce Richardson struct rte_device *dev = NULL; 72299a2dd95SBruce Richardson struct rte_class *cls = NULL; 72399a2dd95SBruce Richardson struct rte_dev_iterator *it; 72499a2dd95SBruce Richardson const char *bus_str = NULL; 72599a2dd95SBruce Richardson 72699a2dd95SBruce Richardson if (bus->dev_iterate == NULL) 72799a2dd95SBruce Richardson return 1; 72899a2dd95SBruce Richardson it = ITCTX(ctx); 72999a2dd95SBruce Richardson bus_str = BUSCTX(ctx); 73099a2dd95SBruce Richardson dev = it->device; 73199a2dd95SBruce Richardson /* it->bus_str != NULL means a bus 73299a2dd95SBruce Richardson * was specified in the devstr. 73399a2dd95SBruce Richardson */ 73499a2dd95SBruce Richardson if (it->bus_str != NULL && bus != it->bus) 73599a2dd95SBruce Richardson return 1; 73699a2dd95SBruce Richardson /* If an error occurred previously, 73799a2dd95SBruce Richardson * no need to test further. 73899a2dd95SBruce Richardson */ 73999a2dd95SBruce Richardson if (rte_errno != 0) 74099a2dd95SBruce Richardson return -1; 74199a2dd95SBruce Richardson if (it->cls_str == NULL) { 74299a2dd95SBruce Richardson dev = bus->dev_iterate(dev, bus_str, it); 74399a2dd95SBruce Richardson goto end; 74499a2dd95SBruce Richardson } 74599a2dd95SBruce Richardson /* cls_str != NULL */ 74699a2dd95SBruce Richardson if (dev == NULL) { 74799a2dd95SBruce Richardson next_dev_on_bus: 74899a2dd95SBruce Richardson dev = bus->dev_iterate(dev, bus_str, it); 74999a2dd95SBruce Richardson it->device = dev; 75099a2dd95SBruce Richardson } 75199a2dd95SBruce Richardson if (dev == NULL) 75299a2dd95SBruce Richardson return 1; 75399a2dd95SBruce Richardson if (it->cls != NULL) 75499a2dd95SBruce Richardson cls = TAILQ_PREV(it->cls, rte_class_list, next); 75599a2dd95SBruce Richardson cls = rte_class_find(cls, class_next_dev_cmp, ctx); 75699a2dd95SBruce Richardson if (cls != NULL) { 75799a2dd95SBruce Richardson it->cls = cls; 75899a2dd95SBruce Richardson goto end; 75999a2dd95SBruce Richardson } 76099a2dd95SBruce Richardson goto next_dev_on_bus; 76199a2dd95SBruce Richardson end: 76299a2dd95SBruce Richardson it->device = dev; 76399a2dd95SBruce Richardson return dev == NULL; 76499a2dd95SBruce Richardson } 76599a2dd95SBruce Richardson struct rte_device * 76699a2dd95SBruce Richardson rte_dev_iterator_next(struct rte_dev_iterator *it) 76799a2dd95SBruce Richardson { 76899a2dd95SBruce Richardson struct rte_bus *bus = NULL; 76999a2dd95SBruce Richardson int old_errno = rte_errno; 77099a2dd95SBruce Richardson char *bus_str = NULL; 77199a2dd95SBruce Richardson char *cls_str = NULL; 77299a2dd95SBruce Richardson 77399a2dd95SBruce Richardson rte_errno = 0; 77499a2dd95SBruce Richardson if (it->bus_str == NULL && it->cls_str == NULL) { 77599a2dd95SBruce Richardson /* Invalid iterator. */ 77699a2dd95SBruce Richardson rte_errno = EINVAL; 77799a2dd95SBruce Richardson return NULL; 77899a2dd95SBruce Richardson } 77999a2dd95SBruce Richardson if (it->bus != NULL) 78099a2dd95SBruce Richardson bus = TAILQ_PREV(it->bus, rte_bus_list, next); 78199a2dd95SBruce Richardson if (it->bus_str != NULL) { 78299a2dd95SBruce Richardson bus_str = dev_str_sane_copy(it->bus_str); 78399a2dd95SBruce Richardson if (bus_str == NULL) 78499a2dd95SBruce Richardson goto out; 78599a2dd95SBruce Richardson } 78699a2dd95SBruce Richardson if (it->cls_str != NULL) { 78799a2dd95SBruce Richardson cls_str = dev_str_sane_copy(it->cls_str); 78899a2dd95SBruce Richardson if (cls_str == NULL) 78999a2dd95SBruce Richardson goto out; 79099a2dd95SBruce Richardson } 79199a2dd95SBruce Richardson while ((bus = rte_bus_find(bus, bus_next_dev_cmp, 79299a2dd95SBruce Richardson CTX(it, bus_str, cls_str)))) { 79399a2dd95SBruce Richardson if (it->device != NULL) { 79499a2dd95SBruce Richardson it->bus = bus; 79599a2dd95SBruce Richardson goto out; 79699a2dd95SBruce Richardson } 79799a2dd95SBruce Richardson if (it->bus_str != NULL || 79899a2dd95SBruce Richardson rte_errno != 0) 79999a2dd95SBruce Richardson break; 80099a2dd95SBruce Richardson } 80199a2dd95SBruce Richardson if (rte_errno == 0) 80299a2dd95SBruce Richardson rte_errno = old_errno; 80399a2dd95SBruce Richardson out: 80499a2dd95SBruce Richardson free(bus_str); 80599a2dd95SBruce Richardson free(cls_str); 80699a2dd95SBruce Richardson return it->device; 80799a2dd95SBruce Richardson } 80899a2dd95SBruce Richardson 80999a2dd95SBruce Richardson int 81099a2dd95SBruce Richardson rte_dev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, 81199a2dd95SBruce Richardson size_t len) 81299a2dd95SBruce Richardson { 81399a2dd95SBruce Richardson if (dev->bus->dma_map == NULL || len == 0) { 81499a2dd95SBruce Richardson rte_errno = ENOTSUP; 81599a2dd95SBruce Richardson return -1; 81699a2dd95SBruce Richardson } 81799a2dd95SBruce Richardson /* Memory must be registered through rte_extmem_* APIs */ 81899a2dd95SBruce Richardson if (rte_mem_virt2memseg_list(addr) == NULL) { 81999a2dd95SBruce Richardson rte_errno = EINVAL; 82099a2dd95SBruce Richardson return -1; 82199a2dd95SBruce Richardson } 82299a2dd95SBruce Richardson 82399a2dd95SBruce Richardson return dev->bus->dma_map(dev, addr, iova, len); 82499a2dd95SBruce Richardson } 82599a2dd95SBruce Richardson 82699a2dd95SBruce Richardson int 82799a2dd95SBruce Richardson rte_dev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, 82899a2dd95SBruce Richardson size_t len) 82999a2dd95SBruce Richardson { 83099a2dd95SBruce Richardson if (dev->bus->dma_unmap == NULL || len == 0) { 83199a2dd95SBruce Richardson rte_errno = ENOTSUP; 83299a2dd95SBruce Richardson return -1; 83399a2dd95SBruce Richardson } 83499a2dd95SBruce Richardson /* Memory must be registered through rte_extmem_* APIs */ 83599a2dd95SBruce Richardson if (rte_mem_virt2memseg_list(addr) == NULL) { 83699a2dd95SBruce Richardson rte_errno = EINVAL; 83799a2dd95SBruce Richardson return -1; 83899a2dd95SBruce Richardson } 83999a2dd95SBruce Richardson 84099a2dd95SBruce Richardson return dev->bus->dma_unmap(dev, addr, iova, len); 84199a2dd95SBruce Richardson } 842