bus/vdev: add lock on device list
[dpdk.git] / drivers / bus / vdev / vdev.c
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2016 RehiveTech. All rights reserved.
3  */
4
5 #include <string.h>
6 #include <inttypes.h>
7 #include <stdio.h>
8 #include <stdlib.h>
9 #include <stdint.h>
10 #include <stdbool.h>
11 #include <sys/queue.h>
12
13 #include <rte_eal.h>
14 #include <rte_dev.h>
15 #include <rte_bus.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>
22
23 #include "rte_bus_vdev.h"
24 #include "vdev_logs.h"
25
26 int vdev_logtype_bus;
27
28 /* Forward declare to access virtual bus name */
29 static struct rte_bus rte_vdev_bus;
30
31 /** Double linked list of virtual device drivers. */
32 TAILQ_HEAD(vdev_device_list, rte_vdev_device);
33
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;
37
38 struct vdev_driver_list vdev_driver_list =
39         TAILQ_HEAD_INITIALIZER(vdev_driver_list);
40
41 struct vdev_custom_scan {
42         TAILQ_ENTRY(vdev_custom_scan) next;
43         rte_vdev_scan_callback callback;
44         void *user_arg;
45 };
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;
50
51 /* register a driver */
52 void
53 rte_vdev_register(struct rte_vdev_driver *driver)
54 {
55         TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
56 }
57
58 /* unregister a driver */
59 void
60 rte_vdev_unregister(struct rte_vdev_driver *driver)
61 {
62         TAILQ_REMOVE(&vdev_driver_list, driver, next);
63 }
64
65 int
66 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
67 {
68         struct vdev_custom_scan *custom_scan;
69
70         rte_spinlock_lock(&vdev_custom_scan_lock);
71
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)
76                         break;
77         }
78
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);
85                 }
86         }
87
88         rte_spinlock_unlock(&vdev_custom_scan_lock);
89
90         return (custom_scan == NULL) ? -1 : 0;
91 }
92
93 int
94 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
95 {
96         struct vdev_custom_scan *custom_scan, *tmp_scan;
97
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))
103                         continue;
104                 TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
105                 free(custom_scan);
106         }
107         rte_spinlock_unlock(&vdev_custom_scan_lock);
108
109         return 0;
110 }
111
112 static int
113 vdev_parse(const char *name, void *addr)
114 {
115         struct rte_vdev_driver **out = addr;
116         struct rte_vdev_driver *driver = NULL;
117
118         TAILQ_FOREACH(driver, &vdev_driver_list, next) {
119                 if (strncmp(driver->driver.name, name,
120                             strlen(driver->driver.name)) == 0)
121                         break;
122                 if (driver->driver.alias &&
123                     strncmp(driver->driver.alias, name,
124                             strlen(driver->driver.alias)) == 0)
125                         break;
126         }
127         if (driver != NULL &&
128             addr != NULL)
129                 *out = driver;
130         return driver == NULL;
131 }
132
133 static int
134 vdev_probe_all_drivers(struct rte_vdev_device *dev)
135 {
136         const char *name;
137         struct rte_vdev_driver *driver;
138         int ret;
139
140         name = rte_vdev_device_name(dev);
141
142         VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name,
143                 rte_vdev_device_name(dev));
144
145         if (vdev_parse(name, &driver))
146                 return -1;
147         dev->device.driver = &driver->driver;
148         ret = driver->probe(dev);
149         if (ret)
150                 dev->device.driver = NULL;
151         return ret;
152 }
153
154 /* The caller shall be responsible for thread-safe */
155 static struct rte_vdev_device *
156 find_vdev(const char *name)
157 {
158         struct rte_vdev_device *dev;
159
160         if (!name)
161                 return NULL;
162
163         TAILQ_FOREACH(dev, &vdev_device_list, next) {
164                 const char *devname = rte_vdev_device_name(dev);
165
166                 if (!strcmp(devname, name))
167                         return dev;
168         }
169
170         return NULL;
171 }
172
173 static struct rte_devargs *
174 alloc_devargs(const char *name, const char *args)
175 {
176         struct rte_devargs *devargs;
177         int ret;
178
179         devargs = calloc(1, sizeof(*devargs));
180         if (!devargs)
181                 return NULL;
182
183         devargs->bus = &rte_vdev_bus;
184         if (args)
185                 devargs->args = strdup(args);
186         else
187                 devargs->args = strdup("");
188
189         ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
190         if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
191                 free(devargs->args);
192                 free(devargs);
193                 return NULL;
194         }
195
196         return devargs;
197 }
198
199 static int
200 insert_vdev(const char *name, const char *args, struct rte_vdev_device **p_dev)
201 {
202         struct rte_vdev_device *dev;
203         struct rte_devargs *devargs;
204         int ret;
205
206         if (name == NULL)
207                 return -EINVAL;
208
209         devargs = alloc_devargs(name, args);
210         if (!devargs)
211                 return -ENOMEM;
212
213         dev = calloc(1, sizeof(*dev));
214         if (!dev) {
215                 ret = -ENOMEM;
216                 goto fail;
217         }
218
219         dev->device.devargs = devargs;
220         dev->device.numa_node = SOCKET_ID_ANY;
221         dev->device.name = devargs->name;
222
223         if (find_vdev(name)) {
224                 ret = -EEXIST;
225                 goto fail;
226         }
227
228         TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
229         TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
230
231         if (p_dev)
232                 *p_dev = dev;
233
234         return 0;
235 fail:
236         free(devargs->args);
237         free(devargs);
238         free(dev);
239         return ret;
240 }
241
242 int
243 rte_vdev_init(const char *name, const char *args)
244 {
245         struct rte_vdev_device *dev;
246         struct rte_devargs *devargs;
247         int ret;
248
249         rte_spinlock_lock(&vdev_device_list_lock);
250         ret = insert_vdev(name, args, &dev);
251         if (ret == 0) {
252                 ret = vdev_probe_all_drivers(dev);
253                 if (ret) {
254                         if (ret > 0)
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);
260                         free(devargs->args);
261                         free(devargs);
262                         free(dev);
263                 }
264         }
265         rte_spinlock_unlock(&vdev_device_list_lock);
266         return ret;
267 }
268
269 static int
270 vdev_remove_driver(struct rte_vdev_device *dev)
271 {
272         const char *name = rte_vdev_device_name(dev);
273         const struct rte_vdev_driver *driver;
274
275         if (!dev->device.driver) {
276                 VDEV_LOG(DEBUG, "no driver attach to device %s\n", name);
277                 return 1;
278         }
279
280         driver = container_of(dev->device.driver, const struct rte_vdev_driver,
281                 driver);
282         return driver->remove(dev);
283 }
284
285 int
286 rte_vdev_uninit(const char *name)
287 {
288         struct rte_vdev_device *dev;
289         struct rte_devargs *devargs;
290         int ret;
291
292         if (name == NULL)
293                 return -EINVAL;
294
295         rte_spinlock_lock(&vdev_device_list_lock);
296
297         dev = find_vdev(name);
298         if (!dev) {
299                 ret = -ENOENT;
300                 goto unlock;
301         }
302
303         ret = vdev_remove_driver(dev);
304         if (ret)
305                 goto unlock;
306
307         TAILQ_REMOVE(&vdev_device_list, dev, next);
308         devargs = dev->device.devargs;
309         TAILQ_REMOVE(&devargs_list, devargs, next);
310         free(devargs->args);
311         free(devargs);
312         free(dev);
313
314 unlock:
315         rte_spinlock_unlock(&vdev_device_list_lock);
316         return ret;
317 }
318
319 static int
320 vdev_scan(void)
321 {
322         struct rte_vdev_device *dev;
323         struct rte_devargs *devargs;
324         struct vdev_custom_scan *custom_scan;
325
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)
330                         /*
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;
336                          */
337                         custom_scan->callback(custom_scan->user_arg);
338         }
339         rte_spinlock_unlock(&vdev_custom_scan_lock);
340
341         /* for virtual devices we scan the devargs_list populated via cmdline */
342         TAILQ_FOREACH(devargs, &devargs_list, next) {
343
344                 if (devargs->bus != &rte_vdev_bus)
345                         continue;
346
347                 dev = calloc(1, sizeof(*dev));
348                 if (!dev)
349                         return -1;
350
351                 rte_spinlock_lock(&vdev_device_list_lock);
352
353                 if (find_vdev(devargs->name)) {
354                         rte_spinlock_unlock(&vdev_device_list_lock);
355                         free(dev);
356                         continue;
357                 }
358
359                 dev->device.devargs = devargs;
360                 dev->device.numa_node = SOCKET_ID_ANY;
361                 dev->device.name = devargs->name;
362
363                 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
364
365                 rte_spinlock_unlock(&vdev_device_list_lock);
366         }
367
368         return 0;
369 }
370
371 static int
372 vdev_probe(void)
373 {
374         struct rte_vdev_device *dev;
375         int ret = 0;
376
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.
382                  */
383
384                 if (dev->device.driver)
385                         continue;
386
387                 if (vdev_probe_all_drivers(dev)) {
388                         VDEV_LOG(ERR, "failed to initialize %s device\n",
389                                 rte_vdev_device_name(dev));
390                         ret = -1;
391                 }
392         }
393
394         return ret;
395 }
396
397 static struct rte_device *
398 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
399                  const void *data)
400 {
401         struct rte_vdev_device *dev;
402
403         rte_spinlock_lock(&vdev_device_list_lock);
404         TAILQ_FOREACH(dev, &vdev_device_list, next) {
405                 if (start && &dev->device == start) {
406                         start = NULL;
407                         continue;
408                 }
409                 if (cmp(&dev->device, data) == 0)
410                         break;
411         }
412         rte_spinlock_unlock(&vdev_device_list_lock);
413
414         return dev ? &dev->device : NULL;
415 }
416
417 static int
418 vdev_plug(struct rte_device *dev)
419 {
420         return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
421 }
422
423 static int
424 vdev_unplug(struct rte_device *dev)
425 {
426         return rte_vdev_uninit(dev->name);
427 }
428
429 static struct rte_bus rte_vdev_bus = {
430         .scan = vdev_scan,
431         .probe = vdev_probe,
432         .find_device = vdev_find_device,
433         .plug = vdev_plug,
434         .unplug = vdev_unplug,
435         .parse = vdev_parse,
436 };
437
438 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
439
440 RTE_INIT(vdev_init_log)
441 {
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);
445 }