1 /* SPDX-License-Identifier: BSD-3-Clause
2 * Copyright(c) 2016 RehiveTech. All rights reserved.
11 #include <sys/queue.h>
16 #include <rte_common.h>
17 #include <rte_devargs.h>
18 #include <rte_memory.h>
19 #include <rte_tailq.h>
20 #include <rte_spinlock.h>
21 #include <rte_errno.h>
23 #include "rte_bus_vdev.h"
24 #include "vdev_logs.h"
28 /* Forward declare to access virtual bus name */
29 static struct rte_bus rte_vdev_bus;
31 /** Double linked list of virtual device drivers. */
32 TAILQ_HEAD(vdev_device_list, rte_vdev_device);
34 static struct vdev_device_list vdev_device_list =
35 TAILQ_HEAD_INITIALIZER(vdev_device_list);
36 static rte_spinlock_t vdev_device_list_lock = RTE_SPINLOCK_INITIALIZER;
38 struct vdev_driver_list vdev_driver_list =
39 TAILQ_HEAD_INITIALIZER(vdev_driver_list);
41 struct vdev_custom_scan {
42 TAILQ_ENTRY(vdev_custom_scan) next;
43 rte_vdev_scan_callback callback;
46 TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
47 static struct vdev_custom_scans vdev_custom_scans =
48 TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
49 static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
51 /* register a driver */
53 rte_vdev_register(struct rte_vdev_driver *driver)
55 TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
58 /* unregister a driver */
60 rte_vdev_unregister(struct rte_vdev_driver *driver)
62 TAILQ_REMOVE(&vdev_driver_list, driver, next);
66 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
68 struct vdev_custom_scan *custom_scan;
70 rte_spinlock_lock(&vdev_custom_scan_lock);
72 /* check if already registered */
73 TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
74 if (custom_scan->callback == callback &&
75 custom_scan->user_arg == user_arg)
79 if (custom_scan == NULL) {
80 custom_scan = malloc(sizeof(struct vdev_custom_scan));
81 if (custom_scan != NULL) {
82 custom_scan->callback = callback;
83 custom_scan->user_arg = user_arg;
84 TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
88 rte_spinlock_unlock(&vdev_custom_scan_lock);
90 return (custom_scan == NULL) ? -1 : 0;
94 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
96 struct vdev_custom_scan *custom_scan, *tmp_scan;
98 rte_spinlock_lock(&vdev_custom_scan_lock);
99 TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next, tmp_scan) {
100 if (custom_scan->callback != callback ||
101 (custom_scan->user_arg != (void *)-1 &&
102 custom_scan->user_arg != user_arg))
104 TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
107 rte_spinlock_unlock(&vdev_custom_scan_lock);
113 vdev_parse(const char *name, void *addr)
115 struct rte_vdev_driver **out = addr;
116 struct rte_vdev_driver *driver = NULL;
118 TAILQ_FOREACH(driver, &vdev_driver_list, next) {
119 if (strncmp(driver->driver.name, name,
120 strlen(driver->driver.name)) == 0)
122 if (driver->driver.alias &&
123 strncmp(driver->driver.alias, name,
124 strlen(driver->driver.alias)) == 0)
127 if (driver != NULL &&
130 return driver == NULL;
134 vdev_probe_all_drivers(struct rte_vdev_device *dev)
137 struct rte_vdev_driver *driver;
140 name = rte_vdev_device_name(dev);
142 VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name,
143 rte_vdev_device_name(dev));
145 if (vdev_parse(name, &driver))
147 dev->device.driver = &driver->driver;
148 ret = driver->probe(dev);
150 dev->device.driver = NULL;
154 /* The caller shall be responsible for thread-safe */
155 static struct rte_vdev_device *
156 find_vdev(const char *name)
158 struct rte_vdev_device *dev;
163 TAILQ_FOREACH(dev, &vdev_device_list, next) {
164 const char *devname = rte_vdev_device_name(dev);
166 if (!strcmp(devname, name))
173 static struct rte_devargs *
174 alloc_devargs(const char *name, const char *args)
176 struct rte_devargs *devargs;
179 devargs = calloc(1, sizeof(*devargs));
183 devargs->bus = &rte_vdev_bus;
185 devargs->args = strdup(args);
187 devargs->args = strdup("");
189 ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
190 if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
200 insert_vdev(const char *name, const char *args, struct rte_vdev_device **p_dev)
202 struct rte_vdev_device *dev;
203 struct rte_devargs *devargs;
209 devargs = alloc_devargs(name, args);
213 dev = calloc(1, sizeof(*dev));
219 dev->device.devargs = devargs;
220 dev->device.numa_node = SOCKET_ID_ANY;
221 dev->device.name = devargs->name;
223 if (find_vdev(name)) {
228 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
229 TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
243 rte_vdev_init(const char *name, const char *args)
245 struct rte_vdev_device *dev;
246 struct rte_devargs *devargs;
249 rte_spinlock_lock(&vdev_device_list_lock);
250 ret = insert_vdev(name, args, &dev);
252 ret = vdev_probe_all_drivers(dev);
255 VDEV_LOG(ERR, "no driver found for %s\n", name);
256 /* If fails, remove it from vdev list */
257 devargs = dev->device.devargs;
258 TAILQ_REMOVE(&vdev_device_list, dev, next);
259 TAILQ_REMOVE(&devargs_list, devargs, next);
265 rte_spinlock_unlock(&vdev_device_list_lock);
270 vdev_remove_driver(struct rte_vdev_device *dev)
272 const char *name = rte_vdev_device_name(dev);
273 const struct rte_vdev_driver *driver;
275 if (!dev->device.driver) {
276 VDEV_LOG(DEBUG, "no driver attach to device %s\n", name);
280 driver = container_of(dev->device.driver, const struct rte_vdev_driver,
282 return driver->remove(dev);
286 rte_vdev_uninit(const char *name)
288 struct rte_vdev_device *dev;
289 struct rte_devargs *devargs;
295 rte_spinlock_lock(&vdev_device_list_lock);
297 dev = find_vdev(name);
303 ret = vdev_remove_driver(dev);
307 TAILQ_REMOVE(&vdev_device_list, dev, next);
308 devargs = dev->device.devargs;
309 TAILQ_REMOVE(&devargs_list, devargs, next);
315 rte_spinlock_unlock(&vdev_device_list_lock);
322 struct rte_vdev_device *dev;
323 struct rte_devargs *devargs;
324 struct vdev_custom_scan *custom_scan;
326 /* call custom scan callbacks if any */
327 rte_spinlock_lock(&vdev_custom_scan_lock);
328 TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
329 if (custom_scan->callback != NULL)
331 * the callback should update devargs list
332 * by calling rte_eal_devargs_insert() with
333 * devargs.bus = rte_bus_find_by_name("vdev");
334 * devargs.type = RTE_DEVTYPE_VIRTUAL;
335 * devargs.policy = RTE_DEV_WHITELISTED;
337 custom_scan->callback(custom_scan->user_arg);
339 rte_spinlock_unlock(&vdev_custom_scan_lock);
341 /* for virtual devices we scan the devargs_list populated via cmdline */
342 TAILQ_FOREACH(devargs, &devargs_list, next) {
344 if (devargs->bus != &rte_vdev_bus)
347 dev = calloc(1, sizeof(*dev));
351 rte_spinlock_lock(&vdev_device_list_lock);
353 if (find_vdev(devargs->name)) {
354 rte_spinlock_unlock(&vdev_device_list_lock);
359 dev->device.devargs = devargs;
360 dev->device.numa_node = SOCKET_ID_ANY;
361 dev->device.name = devargs->name;
363 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
365 rte_spinlock_unlock(&vdev_device_list_lock);
374 struct rte_vdev_device *dev;
377 /* call the init function for each virtual device */
378 TAILQ_FOREACH(dev, &vdev_device_list, next) {
379 /* we don't use the vdev lock here, as it's only used in DPDK
380 * initialization; and we don't want to hold such a lock when
381 * we call each driver probe.
384 if (dev->device.driver)
387 if (vdev_probe_all_drivers(dev)) {
388 VDEV_LOG(ERR, "failed to initialize %s device\n",
389 rte_vdev_device_name(dev));
397 static struct rte_device *
398 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
401 struct rte_vdev_device *dev;
403 rte_spinlock_lock(&vdev_device_list_lock);
404 TAILQ_FOREACH(dev, &vdev_device_list, next) {
405 if (start && &dev->device == start) {
409 if (cmp(&dev->device, data) == 0)
412 rte_spinlock_unlock(&vdev_device_list_lock);
414 return dev ? &dev->device : NULL;
418 vdev_plug(struct rte_device *dev)
420 return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
424 vdev_unplug(struct rte_device *dev)
426 return rte_vdev_uninit(dev->name);
429 static struct rte_bus rte_vdev_bus = {
432 .find_device = vdev_find_device,
434 .unplug = vdev_unplug,
438 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
440 RTE_INIT(vdev_init_log)
442 vdev_logtype_bus = rte_log_register("bus.vdev");
443 if (vdev_logtype_bus >= 0)
444 rte_log_set_level(vdev_logtype_bus, RTE_LOG_NOTICE);