xref: /f-stack/dpdk/drivers/bus/vdev/vdev.c (revision 2d9fd380)
1d30ea906Sjfb8856606 /* SPDX-License-Identifier: BSD-3-Clause
22bfe3f2eSlogwang  * Copyright(c) 2016 RehiveTech. All rights reserved.
32bfe3f2eSlogwang  */
42bfe3f2eSlogwang 
52bfe3f2eSlogwang #include <string.h>
62bfe3f2eSlogwang #include <inttypes.h>
72bfe3f2eSlogwang #include <stdio.h>
82bfe3f2eSlogwang #include <stdlib.h>
92bfe3f2eSlogwang #include <stdint.h>
102bfe3f2eSlogwang #include <stdbool.h>
112bfe3f2eSlogwang #include <sys/queue.h>
122bfe3f2eSlogwang 
132bfe3f2eSlogwang #include <rte_eal.h>
142bfe3f2eSlogwang #include <rte_dev.h>
152bfe3f2eSlogwang #include <rte_bus.h>
162bfe3f2eSlogwang #include <rte_common.h>
172bfe3f2eSlogwang #include <rte_devargs.h>
182bfe3f2eSlogwang #include <rte_memory.h>
19d30ea906Sjfb8856606 #include <rte_tailq.h>
20d30ea906Sjfb8856606 #include <rte_spinlock.h>
21d30ea906Sjfb8856606 #include <rte_string_fns.h>
222bfe3f2eSlogwang #include <rte_errno.h>
232bfe3f2eSlogwang 
242bfe3f2eSlogwang #include "rte_bus_vdev.h"
252bfe3f2eSlogwang #include "vdev_logs.h"
26d30ea906Sjfb8856606 #include "vdev_private.h"
27d30ea906Sjfb8856606 
28d30ea906Sjfb8856606 #define VDEV_MP_KEY	"bus_vdev_mp"
292bfe3f2eSlogwang 
302bfe3f2eSlogwang /* Forward declare to access virtual bus name */
312bfe3f2eSlogwang static struct rte_bus rte_vdev_bus;
322bfe3f2eSlogwang 
332bfe3f2eSlogwang /** Double linked list of virtual device drivers. */
342bfe3f2eSlogwang TAILQ_HEAD(vdev_device_list, rte_vdev_device);
352bfe3f2eSlogwang 
362bfe3f2eSlogwang static struct vdev_device_list vdev_device_list =
372bfe3f2eSlogwang 	TAILQ_HEAD_INITIALIZER(vdev_device_list);
38d30ea906Sjfb8856606 /* The lock needs to be recursive because a vdev can manage another vdev. */
39d30ea906Sjfb8856606 static rte_spinlock_recursive_t vdev_device_list_lock =
40d30ea906Sjfb8856606 	RTE_SPINLOCK_RECURSIVE_INITIALIZER;
41d30ea906Sjfb8856606 
42d30ea906Sjfb8856606 static struct vdev_driver_list vdev_driver_list =
432bfe3f2eSlogwang 	TAILQ_HEAD_INITIALIZER(vdev_driver_list);
442bfe3f2eSlogwang 
45d30ea906Sjfb8856606 struct vdev_custom_scan {
46d30ea906Sjfb8856606 	TAILQ_ENTRY(vdev_custom_scan) next;
47d30ea906Sjfb8856606 	rte_vdev_scan_callback callback;
48d30ea906Sjfb8856606 	void *user_arg;
49d30ea906Sjfb8856606 };
50d30ea906Sjfb8856606 TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
51d30ea906Sjfb8856606 static struct vdev_custom_scans vdev_custom_scans =
52d30ea906Sjfb8856606 	TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
53d30ea906Sjfb8856606 static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
54d30ea906Sjfb8856606 
552bfe3f2eSlogwang /* register a driver */
562bfe3f2eSlogwang void
rte_vdev_register(struct rte_vdev_driver * driver)572bfe3f2eSlogwang rte_vdev_register(struct rte_vdev_driver *driver)
582bfe3f2eSlogwang {
592bfe3f2eSlogwang 	TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
602bfe3f2eSlogwang }
612bfe3f2eSlogwang 
622bfe3f2eSlogwang /* unregister a driver */
632bfe3f2eSlogwang void
rte_vdev_unregister(struct rte_vdev_driver * driver)642bfe3f2eSlogwang rte_vdev_unregister(struct rte_vdev_driver *driver)
652bfe3f2eSlogwang {
662bfe3f2eSlogwang 	TAILQ_REMOVE(&vdev_driver_list, driver, next);
672bfe3f2eSlogwang }
682bfe3f2eSlogwang 
69d30ea906Sjfb8856606 int
rte_vdev_add_custom_scan(rte_vdev_scan_callback callback,void * user_arg)70d30ea906Sjfb8856606 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
71d30ea906Sjfb8856606 {
72d30ea906Sjfb8856606 	struct vdev_custom_scan *custom_scan;
73d30ea906Sjfb8856606 
74d30ea906Sjfb8856606 	rte_spinlock_lock(&vdev_custom_scan_lock);
75d30ea906Sjfb8856606 
76d30ea906Sjfb8856606 	/* check if already registered */
77d30ea906Sjfb8856606 	TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
78d30ea906Sjfb8856606 		if (custom_scan->callback == callback &&
79d30ea906Sjfb8856606 				custom_scan->user_arg == user_arg)
80d30ea906Sjfb8856606 			break;
81d30ea906Sjfb8856606 	}
82d30ea906Sjfb8856606 
83d30ea906Sjfb8856606 	if (custom_scan == NULL) {
84d30ea906Sjfb8856606 		custom_scan = malloc(sizeof(struct vdev_custom_scan));
85d30ea906Sjfb8856606 		if (custom_scan != NULL) {
86d30ea906Sjfb8856606 			custom_scan->callback = callback;
87d30ea906Sjfb8856606 			custom_scan->user_arg = user_arg;
88d30ea906Sjfb8856606 			TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
89d30ea906Sjfb8856606 		}
90d30ea906Sjfb8856606 	}
91d30ea906Sjfb8856606 
92d30ea906Sjfb8856606 	rte_spinlock_unlock(&vdev_custom_scan_lock);
93d30ea906Sjfb8856606 
94d30ea906Sjfb8856606 	return (custom_scan == NULL) ? -1 : 0;
95d30ea906Sjfb8856606 }
96d30ea906Sjfb8856606 
97d30ea906Sjfb8856606 int
rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback,void * user_arg)98d30ea906Sjfb8856606 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
99d30ea906Sjfb8856606 {
100d30ea906Sjfb8856606 	struct vdev_custom_scan *custom_scan, *tmp_scan;
101d30ea906Sjfb8856606 
102d30ea906Sjfb8856606 	rte_spinlock_lock(&vdev_custom_scan_lock);
103d30ea906Sjfb8856606 	TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next, tmp_scan) {
104d30ea906Sjfb8856606 		if (custom_scan->callback != callback ||
105d30ea906Sjfb8856606 				(custom_scan->user_arg != (void *)-1 &&
106d30ea906Sjfb8856606 				custom_scan->user_arg != user_arg))
107d30ea906Sjfb8856606 			continue;
108d30ea906Sjfb8856606 		TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
109d30ea906Sjfb8856606 		free(custom_scan);
110d30ea906Sjfb8856606 	}
111d30ea906Sjfb8856606 	rte_spinlock_unlock(&vdev_custom_scan_lock);
112d30ea906Sjfb8856606 
113d30ea906Sjfb8856606 	return 0;
114d30ea906Sjfb8856606 }
115d30ea906Sjfb8856606 
1162bfe3f2eSlogwang static int
vdev_parse(const char * name,void * addr)1172bfe3f2eSlogwang vdev_parse(const char *name, void *addr)
1182bfe3f2eSlogwang {
1192bfe3f2eSlogwang 	struct rte_vdev_driver **out = addr;
1202bfe3f2eSlogwang 	struct rte_vdev_driver *driver = NULL;
1212bfe3f2eSlogwang 
1222bfe3f2eSlogwang 	TAILQ_FOREACH(driver, &vdev_driver_list, next) {
1232bfe3f2eSlogwang 		if (strncmp(driver->driver.name, name,
1242bfe3f2eSlogwang 			    strlen(driver->driver.name)) == 0)
1252bfe3f2eSlogwang 			break;
1262bfe3f2eSlogwang 		if (driver->driver.alias &&
1272bfe3f2eSlogwang 		    strncmp(driver->driver.alias, name,
1282bfe3f2eSlogwang 			    strlen(driver->driver.alias)) == 0)
1292bfe3f2eSlogwang 			break;
1302bfe3f2eSlogwang 	}
1312bfe3f2eSlogwang 	if (driver != NULL &&
1322bfe3f2eSlogwang 	    addr != NULL)
1332bfe3f2eSlogwang 		*out = driver;
1342bfe3f2eSlogwang 	return driver == NULL;
1352bfe3f2eSlogwang }
1362bfe3f2eSlogwang 
1372bfe3f2eSlogwang static int
vdev_dma_map(struct rte_device * dev,void * addr,uint64_t iova,size_t len)138*2d9fd380Sjfb8856606 vdev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
139*2d9fd380Sjfb8856606 {
140*2d9fd380Sjfb8856606 	struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
141*2d9fd380Sjfb8856606 	const struct rte_vdev_driver *driver;
142*2d9fd380Sjfb8856606 
143*2d9fd380Sjfb8856606 	if (!vdev) {
144*2d9fd380Sjfb8856606 		rte_errno = EINVAL;
145*2d9fd380Sjfb8856606 		return -1;
146*2d9fd380Sjfb8856606 	}
147*2d9fd380Sjfb8856606 
148*2d9fd380Sjfb8856606 	if (!vdev->device.driver) {
149*2d9fd380Sjfb8856606 		VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
150*2d9fd380Sjfb8856606 		return 1;
151*2d9fd380Sjfb8856606 	}
152*2d9fd380Sjfb8856606 
153*2d9fd380Sjfb8856606 	driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
154*2d9fd380Sjfb8856606 			driver);
155*2d9fd380Sjfb8856606 
156*2d9fd380Sjfb8856606 	if (driver->dma_map)
157*2d9fd380Sjfb8856606 		return driver->dma_map(vdev, addr, iova, len);
158*2d9fd380Sjfb8856606 
159*2d9fd380Sjfb8856606 	return 0;
160*2d9fd380Sjfb8856606 }
161*2d9fd380Sjfb8856606 
162*2d9fd380Sjfb8856606 static int
vdev_dma_unmap(struct rte_device * dev,void * addr,uint64_t iova,size_t len)163*2d9fd380Sjfb8856606 vdev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
164*2d9fd380Sjfb8856606 {
165*2d9fd380Sjfb8856606 	struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
166*2d9fd380Sjfb8856606 	const struct rte_vdev_driver *driver;
167*2d9fd380Sjfb8856606 
168*2d9fd380Sjfb8856606 	if (!vdev) {
169*2d9fd380Sjfb8856606 		rte_errno = EINVAL;
170*2d9fd380Sjfb8856606 		return -1;
171*2d9fd380Sjfb8856606 	}
172*2d9fd380Sjfb8856606 
173*2d9fd380Sjfb8856606 	if (!vdev->device.driver) {
174*2d9fd380Sjfb8856606 		VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
175*2d9fd380Sjfb8856606 		return 1;
176*2d9fd380Sjfb8856606 	}
177*2d9fd380Sjfb8856606 
178*2d9fd380Sjfb8856606 	driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
179*2d9fd380Sjfb8856606 			driver);
180*2d9fd380Sjfb8856606 
181*2d9fd380Sjfb8856606 	if (driver->dma_unmap)
182*2d9fd380Sjfb8856606 		return driver->dma_unmap(vdev, addr, iova, len);
183*2d9fd380Sjfb8856606 
184*2d9fd380Sjfb8856606 	return 0;
185*2d9fd380Sjfb8856606 }
186*2d9fd380Sjfb8856606 
187*2d9fd380Sjfb8856606 static int
vdev_probe_all_drivers(struct rte_vdev_device * dev)1882bfe3f2eSlogwang vdev_probe_all_drivers(struct rte_vdev_device *dev)
1892bfe3f2eSlogwang {
1902bfe3f2eSlogwang 	const char *name;
1912bfe3f2eSlogwang 	struct rte_vdev_driver *driver;
1922bfe3f2eSlogwang 	int ret;
1932bfe3f2eSlogwang 
1941646932aSjfb8856606 	if (rte_dev_is_probed(&dev->device))
1951646932aSjfb8856606 		return -EEXIST;
1962bfe3f2eSlogwang 
1971646932aSjfb8856606 	name = rte_vdev_device_name(dev);
1981646932aSjfb8856606 	VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
1992bfe3f2eSlogwang 
2002bfe3f2eSlogwang 	if (vdev_parse(name, &driver))
2012bfe3f2eSlogwang 		return -1;
2025af785ecSfengbojiang(姜凤波) 	ret = driver->probe(dev);
203d30ea906Sjfb8856606 	if (ret == 0)
204d30ea906Sjfb8856606 		dev->device.driver = &driver->driver;
2052bfe3f2eSlogwang 	return ret;
2062bfe3f2eSlogwang }
2072bfe3f2eSlogwang 
208d30ea906Sjfb8856606 /* The caller shall be responsible for thread-safe */
2092bfe3f2eSlogwang static struct rte_vdev_device *
find_vdev(const char * name)2102bfe3f2eSlogwang find_vdev(const char *name)
2112bfe3f2eSlogwang {
2122bfe3f2eSlogwang 	struct rte_vdev_device *dev;
2132bfe3f2eSlogwang 
2142bfe3f2eSlogwang 	if (!name)
2152bfe3f2eSlogwang 		return NULL;
2162bfe3f2eSlogwang 
2172bfe3f2eSlogwang 	TAILQ_FOREACH(dev, &vdev_device_list, next) {
2182bfe3f2eSlogwang 		const char *devname = rte_vdev_device_name(dev);
2192bfe3f2eSlogwang 
220579bf1e2Sjfb8856606 		if (!strcmp(devname, name))
2212bfe3f2eSlogwang 			return dev;
2222bfe3f2eSlogwang 	}
2232bfe3f2eSlogwang 
2242bfe3f2eSlogwang 	return NULL;
2252bfe3f2eSlogwang }
2262bfe3f2eSlogwang 
2272bfe3f2eSlogwang static struct rte_devargs *
alloc_devargs(const char * name,const char * args)2282bfe3f2eSlogwang alloc_devargs(const char *name, const char *args)
2292bfe3f2eSlogwang {
2302bfe3f2eSlogwang 	struct rte_devargs *devargs;
2312bfe3f2eSlogwang 	int ret;
2322bfe3f2eSlogwang 
2332bfe3f2eSlogwang 	devargs = calloc(1, sizeof(*devargs));
2342bfe3f2eSlogwang 	if (!devargs)
2352bfe3f2eSlogwang 		return NULL;
2362bfe3f2eSlogwang 
2372bfe3f2eSlogwang 	devargs->bus = &rte_vdev_bus;
2382bfe3f2eSlogwang 	if (args)
2392bfe3f2eSlogwang 		devargs->args = strdup(args);
2402bfe3f2eSlogwang 	else
2412bfe3f2eSlogwang 		devargs->args = strdup("");
2422bfe3f2eSlogwang 
2434418919fSjohnjiang 	ret = strlcpy(devargs->name, name, sizeof(devargs->name));
2442bfe3f2eSlogwang 	if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
2452bfe3f2eSlogwang 		free(devargs->args);
2462bfe3f2eSlogwang 		free(devargs);
2472bfe3f2eSlogwang 		return NULL;
2482bfe3f2eSlogwang 	}
2492bfe3f2eSlogwang 
2502bfe3f2eSlogwang 	return devargs;
2512bfe3f2eSlogwang }
2522bfe3f2eSlogwang 
253d30ea906Sjfb8856606 static int
insert_vdev(const char * name,const char * args,struct rte_vdev_device ** p_dev,bool init)254d30ea906Sjfb8856606 insert_vdev(const char *name, const char *args,
255d30ea906Sjfb8856606 		struct rte_vdev_device **p_dev,
256d30ea906Sjfb8856606 		bool init)
2572bfe3f2eSlogwang {
2582bfe3f2eSlogwang 	struct rte_vdev_device *dev;
2592bfe3f2eSlogwang 	struct rte_devargs *devargs;
2602bfe3f2eSlogwang 	int ret;
2612bfe3f2eSlogwang 
2622bfe3f2eSlogwang 	if (name == NULL)
2632bfe3f2eSlogwang 		return -EINVAL;
2642bfe3f2eSlogwang 
2652bfe3f2eSlogwang 	devargs = alloc_devargs(name, args);
2662bfe3f2eSlogwang 	if (!devargs)
2672bfe3f2eSlogwang 		return -ENOMEM;
2682bfe3f2eSlogwang 
2692bfe3f2eSlogwang 	dev = calloc(1, sizeof(*dev));
2702bfe3f2eSlogwang 	if (!dev) {
2712bfe3f2eSlogwang 		ret = -ENOMEM;
2722bfe3f2eSlogwang 		goto fail;
2732bfe3f2eSlogwang 	}
2742bfe3f2eSlogwang 
275d30ea906Sjfb8856606 	dev->device.bus = &rte_vdev_bus;
2762bfe3f2eSlogwang 	dev->device.numa_node = SOCKET_ID_ANY;
2772bfe3f2eSlogwang 	dev->device.name = devargs->name;
2782bfe3f2eSlogwang 
279d30ea906Sjfb8856606 	if (find_vdev(name)) {
280d30ea906Sjfb8856606 		/*
281d30ea906Sjfb8856606 		 * A vdev is expected to have only one port.
282d30ea906Sjfb8856606 		 * So there is no reason to try probing again,
283d30ea906Sjfb8856606 		 * even with new arguments.
284d30ea906Sjfb8856606 		 */
285d30ea906Sjfb8856606 		ret = -EEXIST;
2862bfe3f2eSlogwang 		goto fail;
2872bfe3f2eSlogwang 	}
2882bfe3f2eSlogwang 
289d30ea906Sjfb8856606 	if (init)
290d30ea906Sjfb8856606 		rte_devargs_insert(&devargs);
291d30ea906Sjfb8856606 	dev->device.devargs = devargs;
2922bfe3f2eSlogwang 	TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
2935af785ecSfengbojiang(姜凤波) 
294d30ea906Sjfb8856606 	if (p_dev)
295d30ea906Sjfb8856606 		*p_dev = dev;
296d30ea906Sjfb8856606 
297d30ea906Sjfb8856606 	return 0;
2982bfe3f2eSlogwang fail:
2992bfe3f2eSlogwang 	free(devargs->args);
3002bfe3f2eSlogwang 	free(devargs);
3012bfe3f2eSlogwang 	free(dev);
3022bfe3f2eSlogwang 	return ret;
3032bfe3f2eSlogwang }
3042bfe3f2eSlogwang 
305d30ea906Sjfb8856606 int
rte_vdev_init(const char * name,const char * args)306d30ea906Sjfb8856606 rte_vdev_init(const char *name, const char *args)
307d30ea906Sjfb8856606 {
308d30ea906Sjfb8856606 	struct rte_vdev_device *dev;
309d30ea906Sjfb8856606 	int ret;
310d30ea906Sjfb8856606 
311d30ea906Sjfb8856606 	rte_spinlock_recursive_lock(&vdev_device_list_lock);
312d30ea906Sjfb8856606 	ret = insert_vdev(name, args, &dev, true);
313d30ea906Sjfb8856606 	if (ret == 0) {
314d30ea906Sjfb8856606 		ret = vdev_probe_all_drivers(dev);
315d30ea906Sjfb8856606 		if (ret) {
316d30ea906Sjfb8856606 			if (ret > 0)
317d30ea906Sjfb8856606 				VDEV_LOG(ERR, "no driver found for %s", name);
318d30ea906Sjfb8856606 			/* If fails, remove it from vdev list */
319d30ea906Sjfb8856606 			TAILQ_REMOVE(&vdev_device_list, dev, next);
320d30ea906Sjfb8856606 			rte_devargs_remove(dev->device.devargs);
321d30ea906Sjfb8856606 			free(dev);
322d30ea906Sjfb8856606 		}
323d30ea906Sjfb8856606 	}
324d30ea906Sjfb8856606 	rte_spinlock_recursive_unlock(&vdev_device_list_lock);
325d30ea906Sjfb8856606 	return ret;
326d30ea906Sjfb8856606 }
327d30ea906Sjfb8856606 
3282bfe3f2eSlogwang static int
vdev_remove_driver(struct rte_vdev_device * dev)3292bfe3f2eSlogwang vdev_remove_driver(struct rte_vdev_device *dev)
3302bfe3f2eSlogwang {
3312bfe3f2eSlogwang 	const char *name = rte_vdev_device_name(dev);
3322bfe3f2eSlogwang 	const struct rte_vdev_driver *driver;
3332bfe3f2eSlogwang 
3342bfe3f2eSlogwang 	if (!dev->device.driver) {
335d30ea906Sjfb8856606 		VDEV_LOG(DEBUG, "no driver attach to device %s", name);
3362bfe3f2eSlogwang 		return 1;
3372bfe3f2eSlogwang 	}
3382bfe3f2eSlogwang 
3392bfe3f2eSlogwang 	driver = container_of(dev->device.driver, const struct rte_vdev_driver,
3402bfe3f2eSlogwang 		driver);
3412bfe3f2eSlogwang 	return driver->remove(dev);
3422bfe3f2eSlogwang }
3432bfe3f2eSlogwang 
3442bfe3f2eSlogwang int
rte_vdev_uninit(const char * name)3452bfe3f2eSlogwang rte_vdev_uninit(const char *name)
3462bfe3f2eSlogwang {
3472bfe3f2eSlogwang 	struct rte_vdev_device *dev;
3482bfe3f2eSlogwang 	int ret;
3492bfe3f2eSlogwang 
3502bfe3f2eSlogwang 	if (name == NULL)
3512bfe3f2eSlogwang 		return -EINVAL;
3522bfe3f2eSlogwang 
353d30ea906Sjfb8856606 	rte_spinlock_recursive_lock(&vdev_device_list_lock);
3545af785ecSfengbojiang(姜凤波) 
355d30ea906Sjfb8856606 	dev = find_vdev(name);
356d30ea906Sjfb8856606 	if (!dev) {
357d30ea906Sjfb8856606 		ret = -ENOENT;
358d30ea906Sjfb8856606 		goto unlock;
359d30ea906Sjfb8856606 	}
3602bfe3f2eSlogwang 
3612bfe3f2eSlogwang 	ret = vdev_remove_driver(dev);
3622bfe3f2eSlogwang 	if (ret)
363d30ea906Sjfb8856606 		goto unlock;
3642bfe3f2eSlogwang 
3652bfe3f2eSlogwang 	TAILQ_REMOVE(&vdev_device_list, dev, next);
366d30ea906Sjfb8856606 	rte_devargs_remove(dev->device.devargs);
3672bfe3f2eSlogwang 	free(dev);
368d30ea906Sjfb8856606 
369d30ea906Sjfb8856606 unlock:
370d30ea906Sjfb8856606 	rte_spinlock_recursive_unlock(&vdev_device_list_lock);
371d30ea906Sjfb8856606 	return ret;
372d30ea906Sjfb8856606 }
373d30ea906Sjfb8856606 
374d30ea906Sjfb8856606 struct vdev_param {
375d30ea906Sjfb8856606 #define VDEV_SCAN_REQ	1
376d30ea906Sjfb8856606 #define VDEV_SCAN_ONE	2
377d30ea906Sjfb8856606 #define VDEV_SCAN_REP	3
378d30ea906Sjfb8856606 	int type;
379d30ea906Sjfb8856606 	int num;
380d30ea906Sjfb8856606 	char name[RTE_DEV_NAME_MAX_LEN];
381d30ea906Sjfb8856606 };
382d30ea906Sjfb8856606 
383d30ea906Sjfb8856606 static int vdev_plug(struct rte_device *dev);
384d30ea906Sjfb8856606 
385d30ea906Sjfb8856606 /**
386d30ea906Sjfb8856606  * This function works as the action for both primary and secondary process
387d30ea906Sjfb8856606  * for static vdev discovery when a secondary process is booting.
388d30ea906Sjfb8856606  *
389d30ea906Sjfb8856606  * step 1, secondary process sends a sync request to ask for vdev in primary;
390d30ea906Sjfb8856606  * step 2, primary process receives the request, and send vdevs one by one;
391d30ea906Sjfb8856606  * step 3, primary process sends back reply, which indicates how many vdevs
392d30ea906Sjfb8856606  * are sent.
393d30ea906Sjfb8856606  */
394d30ea906Sjfb8856606 static int
vdev_action(const struct rte_mp_msg * mp_msg,const void * peer)395d30ea906Sjfb8856606 vdev_action(const struct rte_mp_msg *mp_msg, const void *peer)
396d30ea906Sjfb8856606 {
397d30ea906Sjfb8856606 	struct rte_vdev_device *dev;
398d30ea906Sjfb8856606 	struct rte_mp_msg mp_resp;
399d30ea906Sjfb8856606 	struct vdev_param *ou = (struct vdev_param *)&mp_resp.param;
400d30ea906Sjfb8856606 	const struct vdev_param *in = (const struct vdev_param *)mp_msg->param;
401d30ea906Sjfb8856606 	const char *devname;
402d30ea906Sjfb8856606 	int num;
403d30ea906Sjfb8856606 	int ret;
404d30ea906Sjfb8856606 
405d30ea906Sjfb8856606 	strlcpy(mp_resp.name, VDEV_MP_KEY, sizeof(mp_resp.name));
406d30ea906Sjfb8856606 	mp_resp.len_param = sizeof(*ou);
407d30ea906Sjfb8856606 	mp_resp.num_fds = 0;
408d30ea906Sjfb8856606 
409d30ea906Sjfb8856606 	switch (in->type) {
410d30ea906Sjfb8856606 	case VDEV_SCAN_REQ:
411d30ea906Sjfb8856606 		ou->type = VDEV_SCAN_ONE;
412d30ea906Sjfb8856606 		ou->num = 1;
413d30ea906Sjfb8856606 		num = 0;
414d30ea906Sjfb8856606 
415d30ea906Sjfb8856606 		rte_spinlock_recursive_lock(&vdev_device_list_lock);
416d30ea906Sjfb8856606 		TAILQ_FOREACH(dev, &vdev_device_list, next) {
417d30ea906Sjfb8856606 			devname = rte_vdev_device_name(dev);
418d30ea906Sjfb8856606 			if (strlen(devname) == 0) {
419d30ea906Sjfb8856606 				VDEV_LOG(INFO, "vdev with no name is not sent");
420d30ea906Sjfb8856606 				continue;
421d30ea906Sjfb8856606 			}
422d30ea906Sjfb8856606 			VDEV_LOG(INFO, "send vdev, %s", devname);
423d30ea906Sjfb8856606 			strlcpy(ou->name, devname, RTE_DEV_NAME_MAX_LEN);
424d30ea906Sjfb8856606 			if (rte_mp_sendmsg(&mp_resp) < 0)
425d30ea906Sjfb8856606 				VDEV_LOG(ERR, "send vdev, %s, failed, %s",
426d30ea906Sjfb8856606 					 devname, strerror(rte_errno));
427d30ea906Sjfb8856606 			num++;
428d30ea906Sjfb8856606 		}
429d30ea906Sjfb8856606 		rte_spinlock_recursive_unlock(&vdev_device_list_lock);
430d30ea906Sjfb8856606 
431d30ea906Sjfb8856606 		ou->type = VDEV_SCAN_REP;
432d30ea906Sjfb8856606 		ou->num = num;
433d30ea906Sjfb8856606 		if (rte_mp_reply(&mp_resp, peer) < 0)
434d30ea906Sjfb8856606 			VDEV_LOG(ERR, "Failed to reply a scan request");
435d30ea906Sjfb8856606 		break;
436d30ea906Sjfb8856606 	case VDEV_SCAN_ONE:
437d30ea906Sjfb8856606 		VDEV_LOG(INFO, "receive vdev, %s", in->name);
438d30ea906Sjfb8856606 		ret = insert_vdev(in->name, NULL, NULL, false);
439d30ea906Sjfb8856606 		if (ret == -EEXIST)
440d30ea906Sjfb8856606 			VDEV_LOG(DEBUG, "device already exist, %s", in->name);
441d30ea906Sjfb8856606 		else if (ret < 0)
442d30ea906Sjfb8856606 			VDEV_LOG(ERR, "failed to add vdev, %s", in->name);
443d30ea906Sjfb8856606 		break;
444d30ea906Sjfb8856606 	default:
445d30ea906Sjfb8856606 		VDEV_LOG(ERR, "vdev cannot recognize this message");
446d30ea906Sjfb8856606 	}
447d30ea906Sjfb8856606 
4482bfe3f2eSlogwang 	return 0;
4492bfe3f2eSlogwang }
4502bfe3f2eSlogwang 
4512bfe3f2eSlogwang static int
vdev_scan(void)4522bfe3f2eSlogwang vdev_scan(void)
4532bfe3f2eSlogwang {
4542bfe3f2eSlogwang 	struct rte_vdev_device *dev;
4552bfe3f2eSlogwang 	struct rte_devargs *devargs;
456d30ea906Sjfb8856606 	struct vdev_custom_scan *custom_scan;
457d30ea906Sjfb8856606 
458d30ea906Sjfb8856606 	if (rte_mp_action_register(VDEV_MP_KEY, vdev_action) < 0 &&
459d30ea906Sjfb8856606 	    rte_errno != EEXIST) {
4604418919fSjohnjiang 		/* for primary, unsupported IPC is not an error */
4614418919fSjohnjiang 		if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
4624418919fSjohnjiang 				rte_errno == ENOTSUP)
4634418919fSjohnjiang 			goto scan;
464d30ea906Sjfb8856606 		VDEV_LOG(ERR, "Failed to add vdev mp action");
465d30ea906Sjfb8856606 		return -1;
466d30ea906Sjfb8856606 	}
467d30ea906Sjfb8856606 
468d30ea906Sjfb8856606 	if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
469d30ea906Sjfb8856606 		struct rte_mp_msg mp_req, *mp_rep;
470d30ea906Sjfb8856606 		struct rte_mp_reply mp_reply;
471d30ea906Sjfb8856606 		struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
472d30ea906Sjfb8856606 		struct vdev_param *req = (struct vdev_param *)mp_req.param;
473d30ea906Sjfb8856606 		struct vdev_param *resp;
474d30ea906Sjfb8856606 
475d30ea906Sjfb8856606 		strlcpy(mp_req.name, VDEV_MP_KEY, sizeof(mp_req.name));
476d30ea906Sjfb8856606 		mp_req.len_param = sizeof(*req);
477d30ea906Sjfb8856606 		mp_req.num_fds = 0;
478d30ea906Sjfb8856606 		req->type = VDEV_SCAN_REQ;
479d30ea906Sjfb8856606 		if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0 &&
480d30ea906Sjfb8856606 		    mp_reply.nb_received == 1) {
481d30ea906Sjfb8856606 			mp_rep = &mp_reply.msgs[0];
482d30ea906Sjfb8856606 			resp = (struct vdev_param *)mp_rep->param;
483d30ea906Sjfb8856606 			VDEV_LOG(INFO, "Received %d vdevs", resp->num);
484d30ea906Sjfb8856606 			free(mp_reply.msgs);
485d30ea906Sjfb8856606 		} else
486d30ea906Sjfb8856606 			VDEV_LOG(ERR, "Failed to request vdev from primary");
487d30ea906Sjfb8856606 
488d30ea906Sjfb8856606 		/* Fall through to allow private vdevs in secondary process */
489d30ea906Sjfb8856606 	}
490d30ea906Sjfb8856606 
4914418919fSjohnjiang scan:
492d30ea906Sjfb8856606 	/* call custom scan callbacks if any */
493d30ea906Sjfb8856606 	rte_spinlock_lock(&vdev_custom_scan_lock);
494d30ea906Sjfb8856606 	TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
495d30ea906Sjfb8856606 		if (custom_scan->callback != NULL)
496d30ea906Sjfb8856606 			/*
497d30ea906Sjfb8856606 			 * the callback should update devargs list
498d30ea906Sjfb8856606 			 * by calling rte_devargs_insert() with
499d30ea906Sjfb8856606 			 *     devargs.bus = rte_bus_find_by_name("vdev");
500d30ea906Sjfb8856606 			 *     devargs.type = RTE_DEVTYPE_VIRTUAL;
501*2d9fd380Sjfb8856606 			 *     devargs.policy = RTE_DEV_ALLOWED;
502d30ea906Sjfb8856606 			 */
503d30ea906Sjfb8856606 			custom_scan->callback(custom_scan->user_arg);
504d30ea906Sjfb8856606 	}
505d30ea906Sjfb8856606 	rte_spinlock_unlock(&vdev_custom_scan_lock);
5062bfe3f2eSlogwang 
5072bfe3f2eSlogwang 	/* for virtual devices we scan the devargs_list populated via cmdline */
508d30ea906Sjfb8856606 	RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
5092bfe3f2eSlogwang 
5102bfe3f2eSlogwang 		dev = calloc(1, sizeof(*dev));
5112bfe3f2eSlogwang 		if (!dev)
5122bfe3f2eSlogwang 			return -1;
5132bfe3f2eSlogwang 
514d30ea906Sjfb8856606 		rte_spinlock_recursive_lock(&vdev_device_list_lock);
515d30ea906Sjfb8856606 
516d30ea906Sjfb8856606 		if (find_vdev(devargs->name)) {
517d30ea906Sjfb8856606 			rte_spinlock_recursive_unlock(&vdev_device_list_lock);
518d30ea906Sjfb8856606 			free(dev);
519d30ea906Sjfb8856606 			continue;
520d30ea906Sjfb8856606 		}
521d30ea906Sjfb8856606 
522d30ea906Sjfb8856606 		dev->device.bus = &rte_vdev_bus;
5232bfe3f2eSlogwang 		dev->device.devargs = devargs;
5242bfe3f2eSlogwang 		dev->device.numa_node = SOCKET_ID_ANY;
5252bfe3f2eSlogwang 		dev->device.name = devargs->name;
5262bfe3f2eSlogwang 
5272bfe3f2eSlogwang 		TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
528d30ea906Sjfb8856606 
529d30ea906Sjfb8856606 		rte_spinlock_recursive_unlock(&vdev_device_list_lock);
5302bfe3f2eSlogwang 	}
5312bfe3f2eSlogwang 
5322bfe3f2eSlogwang 	return 0;
5332bfe3f2eSlogwang }
5342bfe3f2eSlogwang 
5352bfe3f2eSlogwang static int
vdev_probe(void)5362bfe3f2eSlogwang vdev_probe(void)
5372bfe3f2eSlogwang {
5382bfe3f2eSlogwang 	struct rte_vdev_device *dev;
5391646932aSjfb8856606 	int r, ret = 0;
5402bfe3f2eSlogwang 
5412bfe3f2eSlogwang 	/* call the init function for each virtual device */
5422bfe3f2eSlogwang 	TAILQ_FOREACH(dev, &vdev_device_list, next) {
543d30ea906Sjfb8856606 		/* we don't use the vdev lock here, as it's only used in DPDK
544d30ea906Sjfb8856606 		 * initialization; and we don't want to hold such a lock when
545d30ea906Sjfb8856606 		 * we call each driver probe.
546d30ea906Sjfb8856606 		 */
5472bfe3f2eSlogwang 
5481646932aSjfb8856606 		r = vdev_probe_all_drivers(dev);
5491646932aSjfb8856606 		if (r != 0) {
5501646932aSjfb8856606 			if (r == -EEXIST)
5512bfe3f2eSlogwang 				continue;
552d30ea906Sjfb8856606 			VDEV_LOG(ERR, "failed to initialize %s device",
5532bfe3f2eSlogwang 				rte_vdev_device_name(dev));
5542bfe3f2eSlogwang 			ret = -1;
5552bfe3f2eSlogwang 		}
5562bfe3f2eSlogwang 	}
5572bfe3f2eSlogwang 
5582bfe3f2eSlogwang 	return ret;
5592bfe3f2eSlogwang }
5602bfe3f2eSlogwang 
561d30ea906Sjfb8856606 struct rte_device *
rte_vdev_find_device(const struct rte_device * start,rte_dev_cmp_t cmp,const void * data)562d30ea906Sjfb8856606 rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
5632bfe3f2eSlogwang 		     const void *data)
5642bfe3f2eSlogwang {
565d30ea906Sjfb8856606 	const struct rte_vdev_device *vstart;
5662bfe3f2eSlogwang 	struct rte_vdev_device *dev;
5672bfe3f2eSlogwang 
568d30ea906Sjfb8856606 	rte_spinlock_recursive_lock(&vdev_device_list_lock);
569d30ea906Sjfb8856606 	if (start != NULL) {
570d30ea906Sjfb8856606 		vstart = RTE_DEV_TO_VDEV_CONST(start);
571d30ea906Sjfb8856606 		dev = TAILQ_NEXT(vstart, next);
572d30ea906Sjfb8856606 	} else {
573d30ea906Sjfb8856606 		dev = TAILQ_FIRST(&vdev_device_list);
5742bfe3f2eSlogwang 	}
575d30ea906Sjfb8856606 	while (dev != NULL) {
5762bfe3f2eSlogwang 		if (cmp(&dev->device, data) == 0)
577d30ea906Sjfb8856606 			break;
578d30ea906Sjfb8856606 		dev = TAILQ_NEXT(dev, next);
5792bfe3f2eSlogwang 	}
580d30ea906Sjfb8856606 	rte_spinlock_recursive_unlock(&vdev_device_list_lock);
581d30ea906Sjfb8856606 
582d30ea906Sjfb8856606 	return dev ? &dev->device : NULL;
5832bfe3f2eSlogwang }
5842bfe3f2eSlogwang 
5852bfe3f2eSlogwang static int
vdev_plug(struct rte_device * dev)5862bfe3f2eSlogwang vdev_plug(struct rte_device *dev)
5872bfe3f2eSlogwang {
5882bfe3f2eSlogwang 	return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
5892bfe3f2eSlogwang }
5902bfe3f2eSlogwang 
5912bfe3f2eSlogwang static int
vdev_unplug(struct rte_device * dev)5922bfe3f2eSlogwang vdev_unplug(struct rte_device *dev)
5932bfe3f2eSlogwang {
5942bfe3f2eSlogwang 	return rte_vdev_uninit(dev->name);
5952bfe3f2eSlogwang }
5962bfe3f2eSlogwang 
5972bfe3f2eSlogwang static struct rte_bus rte_vdev_bus = {
5982bfe3f2eSlogwang 	.scan = vdev_scan,
5992bfe3f2eSlogwang 	.probe = vdev_probe,
600d30ea906Sjfb8856606 	.find_device = rte_vdev_find_device,
6012bfe3f2eSlogwang 	.plug = vdev_plug,
6022bfe3f2eSlogwang 	.unplug = vdev_unplug,
6032bfe3f2eSlogwang 	.parse = vdev_parse,
604*2d9fd380Sjfb8856606 	.dma_map = vdev_dma_map,
605*2d9fd380Sjfb8856606 	.dma_unmap = vdev_dma_unmap,
606d30ea906Sjfb8856606 	.dev_iterate = rte_vdev_dev_iterate,
6072bfe3f2eSlogwang };
6082bfe3f2eSlogwang 
6092bfe3f2eSlogwang RTE_REGISTER_BUS(vdev, rte_vdev_bus);
610*2d9fd380Sjfb8856606 RTE_LOG_REGISTER(vdev_logtype_bus, bus.vdev, NOTICE);
611