xref: /dpdk/lib/eal/common/eal_common_dev.c (revision 97bbdba31d149fdf1e414b6008167d76bf35ccdd)
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