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