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