New upstream version 18.02
[deb_dpdk.git] / drivers / bus / vdev / vdev.c
1 /*-
2  *   BSD LICENSE
3  *
4  *   Copyright(c) 2016 RehiveTech. All rights reserved.
5  *
6  *   Redistribution and use in source and binary forms, with or without
7  *   modification, are permitted provided that the following conditions
8  *   are met:
9  *
10  *     * Redistributions of source code must retain the above copyright
11  *       notice, this list of conditions and the following disclaimer.
12  *     * Redistributions in binary form must reproduce the above copyright
13  *       notice, this list of conditions and the following disclaimer in
14  *       the documentation and/or other materials provided with the
15  *       distribution.
16  *     * Neither the name of RehiveTech nor the names of its
17  *       contributors may be used to endorse or promote products derived
18  *       from this software without specific prior written permission.
19  *
20  *   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
21  *   "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
22  *   LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
23  *   A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
24  *   OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
25  *   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
26  *   LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
27  *   DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
28  *   THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
29  *   (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
30  *   OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
31  */
32
33 #include <string.h>
34 #include <inttypes.h>
35 #include <stdio.h>
36 #include <stdlib.h>
37 #include <stdint.h>
38 #include <stdbool.h>
39 #include <sys/queue.h>
40
41 #include <rte_eal.h>
42 #include <rte_dev.h>
43 #include <rte_bus.h>
44 #include <rte_common.h>
45 #include <rte_devargs.h>
46 #include <rte_memory.h>
47 #include <rte_tailq.h>
48 #include <rte_spinlock.h>
49 #include <rte_errno.h>
50
51 #include "rte_bus_vdev.h"
52 #include "vdev_logs.h"
53
54 int vdev_logtype_bus;
55
56 /* Forward declare to access virtual bus name */
57 static struct rte_bus rte_vdev_bus;
58
59 /** Double linked list of virtual device drivers. */
60 TAILQ_HEAD(vdev_device_list, rte_vdev_device);
61
62 static struct vdev_device_list vdev_device_list =
63         TAILQ_HEAD_INITIALIZER(vdev_device_list);
64 struct vdev_driver_list vdev_driver_list =
65         TAILQ_HEAD_INITIALIZER(vdev_driver_list);
66
67 struct vdev_custom_scan {
68         TAILQ_ENTRY(vdev_custom_scan) next;
69         rte_vdev_scan_callback callback;
70         void *user_arg;
71 };
72 TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
73 static struct vdev_custom_scans vdev_custom_scans =
74         TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
75 static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
76
77 /* register a driver */
78 void
79 rte_vdev_register(struct rte_vdev_driver *driver)
80 {
81         TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
82 }
83
84 /* unregister a driver */
85 void
86 rte_vdev_unregister(struct rte_vdev_driver *driver)
87 {
88         TAILQ_REMOVE(&vdev_driver_list, driver, next);
89 }
90
91 int
92 rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
93 {
94         struct vdev_custom_scan *custom_scan;
95
96         rte_spinlock_lock(&vdev_custom_scan_lock);
97
98         /* check if already registered */
99         TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
100                 if (custom_scan->callback == callback &&
101                                 custom_scan->user_arg == user_arg)
102                         break;
103         }
104
105         if (custom_scan == NULL) {
106                 custom_scan = malloc(sizeof(struct vdev_custom_scan));
107                 if (custom_scan != NULL) {
108                         custom_scan->callback = callback;
109                         custom_scan->user_arg = user_arg;
110                         TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
111                 }
112         }
113
114         rte_spinlock_unlock(&vdev_custom_scan_lock);
115
116         return (custom_scan == NULL) ? -1 : 0;
117 }
118
119 int
120 rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
121 {
122         struct vdev_custom_scan *custom_scan, *tmp_scan;
123
124         rte_spinlock_lock(&vdev_custom_scan_lock);
125         TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next, tmp_scan) {
126                 if (custom_scan->callback != callback ||
127                                 (custom_scan->user_arg != (void *)-1 &&
128                                 custom_scan->user_arg != user_arg))
129                         continue;
130                 TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
131                 free(custom_scan);
132         }
133         rte_spinlock_unlock(&vdev_custom_scan_lock);
134
135         return 0;
136 }
137
138 static int
139 vdev_parse(const char *name, void *addr)
140 {
141         struct rte_vdev_driver **out = addr;
142         struct rte_vdev_driver *driver = NULL;
143
144         TAILQ_FOREACH(driver, &vdev_driver_list, next) {
145                 if (strncmp(driver->driver.name, name,
146                             strlen(driver->driver.name)) == 0)
147                         break;
148                 if (driver->driver.alias &&
149                     strncmp(driver->driver.alias, name,
150                             strlen(driver->driver.alias)) == 0)
151                         break;
152         }
153         if (driver != NULL &&
154             addr != NULL)
155                 *out = driver;
156         return driver == NULL;
157 }
158
159 static int
160 vdev_probe_all_drivers(struct rte_vdev_device *dev)
161 {
162         const char *name;
163         struct rte_vdev_driver *driver;
164         int ret;
165
166         name = rte_vdev_device_name(dev);
167
168         VDEV_LOG(DEBUG, "Search driver %s to probe device %s\n", name,
169                 rte_vdev_device_name(dev));
170
171         if (vdev_parse(name, &driver))
172                 return -1;
173         dev->device.driver = &driver->driver;
174         ret = driver->probe(dev);
175         if (ret)
176                 dev->device.driver = NULL;
177         return ret;
178 }
179
180 static struct rte_vdev_device *
181 find_vdev(const char *name)
182 {
183         struct rte_vdev_device *dev;
184
185         if (!name)
186                 return NULL;
187
188         TAILQ_FOREACH(dev, &vdev_device_list, next) {
189                 const char *devname = rte_vdev_device_name(dev);
190
191                 if (!strncmp(devname, name, strlen(name)))
192                         return dev;
193         }
194
195         return NULL;
196 }
197
198 static struct rte_devargs *
199 alloc_devargs(const char *name, const char *args)
200 {
201         struct rte_devargs *devargs;
202         int ret;
203
204         devargs = calloc(1, sizeof(*devargs));
205         if (!devargs)
206                 return NULL;
207
208         devargs->bus = &rte_vdev_bus;
209         if (args)
210                 devargs->args = strdup(args);
211         else
212                 devargs->args = strdup("");
213
214         ret = snprintf(devargs->name, sizeof(devargs->name), "%s", name);
215         if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
216                 free(devargs->args);
217                 free(devargs);
218                 return NULL;
219         }
220
221         return devargs;
222 }
223
224 int
225 rte_vdev_init(const char *name, const char *args)
226 {
227         struct rte_vdev_device *dev;
228         struct rte_devargs *devargs;
229         int ret;
230
231         if (name == NULL)
232                 return -EINVAL;
233
234         dev = find_vdev(name);
235         if (dev)
236                 return -EEXIST;
237
238         devargs = alloc_devargs(name, args);
239         if (!devargs)
240                 return -ENOMEM;
241
242         dev = calloc(1, sizeof(*dev));
243         if (!dev) {
244                 ret = -ENOMEM;
245                 goto fail;
246         }
247
248         dev->device.devargs = devargs;
249         dev->device.numa_node = SOCKET_ID_ANY;
250         dev->device.name = devargs->name;
251
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                 goto fail;
257         }
258
259         TAILQ_INSERT_TAIL(&devargs_list, devargs, next);
260
261         TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
262         return 0;
263
264 fail:
265         free(devargs->args);
266         free(devargs);
267         free(dev);
268         return ret;
269 }
270
271 static int
272 vdev_remove_driver(struct rte_vdev_device *dev)
273 {
274         const char *name = rte_vdev_device_name(dev);
275         const struct rte_vdev_driver *driver;
276
277         if (!dev->device.driver) {
278                 VDEV_LOG(DEBUG, "no driver attach to device %s\n", name);
279                 return 1;
280         }
281
282         driver = container_of(dev->device.driver, const struct rte_vdev_driver,
283                 driver);
284         return driver->remove(dev);
285 }
286
287 int
288 rte_vdev_uninit(const char *name)
289 {
290         struct rte_vdev_device *dev;
291         struct rte_devargs *devargs;
292         int ret;
293
294         if (name == NULL)
295                 return -EINVAL;
296
297         dev = find_vdev(name);
298         if (!dev)
299                 return -ENOENT;
300
301         devargs = dev->device.devargs;
302
303         ret = vdev_remove_driver(dev);
304         if (ret)
305                 return ret;
306
307         TAILQ_REMOVE(&vdev_device_list, dev, next);
308
309         TAILQ_REMOVE(&devargs_list, devargs, next);
310
311         free(devargs->args);
312         free(devargs);
313         free(dev);
314         return 0;
315 }
316
317 static int
318 vdev_scan(void)
319 {
320         struct rte_vdev_device *dev;
321         struct rte_devargs *devargs;
322         struct vdev_custom_scan *custom_scan;
323
324         /* call custom scan callbacks if any */
325         rte_spinlock_lock(&vdev_custom_scan_lock);
326         TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
327                 if (custom_scan->callback != NULL)
328                         /*
329                          * the callback should update devargs list
330                          * by calling rte_eal_devargs_insert() with
331                          *     devargs.bus = rte_bus_find_by_name("vdev");
332                          *     devargs.type = RTE_DEVTYPE_VIRTUAL;
333                          *     devargs.policy = RTE_DEV_WHITELISTED;
334                          */
335                         custom_scan->callback(custom_scan->user_arg);
336         }
337         rte_spinlock_unlock(&vdev_custom_scan_lock);
338
339         /* for virtual devices we scan the devargs_list populated via cmdline */
340         TAILQ_FOREACH(devargs, &devargs_list, next) {
341
342                 if (devargs->bus != &rte_vdev_bus)
343                         continue;
344
345                 dev = find_vdev(devargs->name);
346                 if (dev)
347                         continue;
348
349                 dev = calloc(1, sizeof(*dev));
350                 if (!dev)
351                         return -1;
352
353                 dev->device.devargs = devargs;
354                 dev->device.numa_node = SOCKET_ID_ANY;
355                 dev->device.name = devargs->name;
356
357                 TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
358         }
359
360         return 0;
361 }
362
363 static int
364 vdev_probe(void)
365 {
366         struct rte_vdev_device *dev;
367         int ret = 0;
368
369         /* call the init function for each virtual device */
370         TAILQ_FOREACH(dev, &vdev_device_list, next) {
371
372                 if (dev->device.driver)
373                         continue;
374
375                 if (vdev_probe_all_drivers(dev)) {
376                         VDEV_LOG(ERR, "failed to initialize %s device\n",
377                                 rte_vdev_device_name(dev));
378                         ret = -1;
379                 }
380         }
381
382         return ret;
383 }
384
385 static struct rte_device *
386 vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
387                  const void *data)
388 {
389         struct rte_vdev_device *dev;
390
391         TAILQ_FOREACH(dev, &vdev_device_list, next) {
392                 if (start && &dev->device == start) {
393                         start = NULL;
394                         continue;
395                 }
396                 if (cmp(&dev->device, data) == 0)
397                         return &dev->device;
398         }
399         return NULL;
400 }
401
402 static int
403 vdev_plug(struct rte_device *dev)
404 {
405         return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
406 }
407
408 static int
409 vdev_unplug(struct rte_device *dev)
410 {
411         return rte_vdev_uninit(dev->name);
412 }
413
414 static struct rte_bus rte_vdev_bus = {
415         .scan = vdev_scan,
416         .probe = vdev_probe,
417         .find_device = vdev_find_device,
418         .plug = vdev_plug,
419         .unplug = vdev_unplug,
420         .parse = vdev_parse,
421 };
422
423 RTE_REGISTER_BUS(vdev, rte_vdev_bus);
424
425 RTE_INIT(vdev_init_log)
426 {
427         vdev_logtype_bus = rte_log_register("bus.vdev");
428         if (vdev_logtype_bus >= 0)
429                 rte_log_set_level(vdev_logtype_bus, RTE_LOG_NOTICE);
430 }