Branch data Line data Source code
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 <eal_export.h>
14 : : #include <rte_eal.h>
15 : : #include <dev_driver.h>
16 : : #include <bus_driver.h>
17 : : #include <rte_common.h>
18 : : #include <rte_devargs.h>
19 : : #include <rte_memory.h>
20 : : #include <rte_tailq.h>
21 : : #include <rte_spinlock.h>
22 : : #include <rte_string_fns.h>
23 : : #include <rte_errno.h>
24 : :
25 : : #include "bus_vdev_driver.h"
26 : : #include "vdev_logs.h"
27 : : #include "vdev_private.h"
28 : :
29 : : #define VDEV_MP_KEY "bus_vdev_mp"
30 : :
31 : : /* Forward declare to access virtual bus name */
32 : : static struct rte_bus rte_vdev_bus;
33 : :
34 : :
35 : : static TAILQ_HEAD(, rte_vdev_device) vdev_device_list =
36 : : TAILQ_HEAD_INITIALIZER(vdev_device_list);
37 : : /* The lock needs to be recursive because a vdev can manage another vdev. */
38 : : static rte_spinlock_recursive_t vdev_device_list_lock =
39 : : RTE_SPINLOCK_RECURSIVE_INITIALIZER;
40 : :
41 : : static TAILQ_HEAD(, rte_vdev_driver) vdev_driver_list =
42 : : TAILQ_HEAD_INITIALIZER(vdev_driver_list);
43 : :
44 : : struct vdev_custom_scan {
45 : : TAILQ_ENTRY(vdev_custom_scan) next;
46 : : rte_vdev_scan_callback callback;
47 : : void *user_arg;
48 : : };
49 : : TAILQ_HEAD(vdev_custom_scans, vdev_custom_scan);
50 : : static struct vdev_custom_scans vdev_custom_scans =
51 : : TAILQ_HEAD_INITIALIZER(vdev_custom_scans);
52 : : static rte_spinlock_t vdev_custom_scan_lock = RTE_SPINLOCK_INITIALIZER;
53 : :
54 : : /* register a driver */
55 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdev_register)
56 : : void
57 : 10080 : rte_vdev_register(struct rte_vdev_driver *driver)
58 : : {
59 : 10080 : TAILQ_INSERT_TAIL(&vdev_driver_list, driver, next);
60 : 10080 : }
61 : :
62 : : /* unregister a driver */
63 : : RTE_EXPORT_INTERNAL_SYMBOL(rte_vdev_unregister)
64 : : void
65 : 0 : rte_vdev_unregister(struct rte_vdev_driver *driver)
66 : : {
67 [ # # ]: 0 : TAILQ_REMOVE(&vdev_driver_list, driver, next);
68 : 0 : }
69 : :
70 : : RTE_EXPORT_SYMBOL(rte_vdev_add_custom_scan)
71 : : int
72 : 0 : rte_vdev_add_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
73 : : {
74 : : struct vdev_custom_scan *custom_scan;
75 : :
76 : : rte_spinlock_lock(&vdev_custom_scan_lock);
77 : :
78 : : /* check if already registered */
79 [ # # ]: 0 : TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
80 [ # # ]: 0 : if (custom_scan->callback == callback &&
81 [ # # ]: 0 : custom_scan->user_arg == user_arg)
82 : : break;
83 : : }
84 : :
85 [ # # ]: 0 : if (custom_scan == NULL) {
86 : 0 : custom_scan = malloc(sizeof(struct vdev_custom_scan));
87 [ # # ]: 0 : if (custom_scan != NULL) {
88 : 0 : custom_scan->callback = callback;
89 : 0 : custom_scan->user_arg = user_arg;
90 : 0 : TAILQ_INSERT_TAIL(&vdev_custom_scans, custom_scan, next);
91 : : }
92 : : }
93 : :
94 : : rte_spinlock_unlock(&vdev_custom_scan_lock);
95 : :
96 [ # # ]: 0 : return (custom_scan == NULL) ? -1 : 0;
97 : : }
98 : :
99 : : RTE_EXPORT_SYMBOL(rte_vdev_remove_custom_scan)
100 : : int
101 : 0 : rte_vdev_remove_custom_scan(rte_vdev_scan_callback callback, void *user_arg)
102 : : {
103 : : struct vdev_custom_scan *custom_scan, *tmp_scan;
104 : :
105 : : rte_spinlock_lock(&vdev_custom_scan_lock);
106 [ # # ]: 0 : RTE_TAILQ_FOREACH_SAFE(custom_scan, &vdev_custom_scans, next,
107 : : tmp_scan) {
108 [ # # ]: 0 : if (custom_scan->callback != callback ||
109 [ # # # # ]: 0 : (custom_scan->user_arg != (void *)-1 &&
110 : : custom_scan->user_arg != user_arg))
111 : 0 : continue;
112 [ # # ]: 0 : TAILQ_REMOVE(&vdev_custom_scans, custom_scan, next);
113 : 0 : free(custom_scan);
114 : : }
115 : : rte_spinlock_unlock(&vdev_custom_scan_lock);
116 : :
117 : 0 : return 0;
118 : : }
119 : :
120 : : static int
121 : 66 : vdev_parse(const char *name, void *addr)
122 : : {
123 : : struct rte_vdev_driver **out = addr;
124 : : struct rte_vdev_driver *driver = NULL;
125 : :
126 [ + + ]: 1476 : TAILQ_FOREACH(driver, &vdev_driver_list, next) {
127 [ + + ]: 1461 : if (strncmp(driver->driver.name, name,
128 : : strlen(driver->driver.name)) == 0)
129 : : break;
130 [ + + ]: 1412 : if (driver->driver.alias &&
131 [ + + ]: 512 : strncmp(driver->driver.alias, name,
132 : : strlen(driver->driver.alias)) == 0)
133 : : break;
134 : : }
135 : 66 : if (driver != NULL &&
136 [ + + ]: 66 : addr != NULL)
137 : 37 : *out = driver;
138 : 66 : return driver == NULL;
139 : : }
140 : :
141 : : static int
142 : 0 : vdev_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
143 : : {
144 : 0 : struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
145 : : const struct rte_vdev_driver *driver;
146 : :
147 [ # # ]: 0 : if (!vdev) {
148 : 0 : rte_errno = EINVAL;
149 : 0 : return -1;
150 : : }
151 : :
152 [ # # ]: 0 : if (!vdev->device.driver) {
153 : 0 : VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
154 : 0 : return 1;
155 : : }
156 : :
157 : 0 : driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
158 : : driver);
159 : :
160 [ # # ]: 0 : if (driver->dma_map)
161 : 0 : return driver->dma_map(vdev, addr, iova, len);
162 : :
163 : : return 0;
164 : : }
165 : :
166 : : static int
167 : 0 : vdev_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
168 : : {
169 : 0 : struct rte_vdev_device *vdev = RTE_DEV_TO_VDEV(dev);
170 : : const struct rte_vdev_driver *driver;
171 : :
172 [ # # ]: 0 : if (!vdev) {
173 : 0 : rte_errno = EINVAL;
174 : 0 : return -1;
175 : : }
176 : :
177 [ # # ]: 0 : if (!vdev->device.driver) {
178 : 0 : VDEV_LOG(DEBUG, "no driver attach to device %s", dev->name);
179 : 0 : return 1;
180 : : }
181 : :
182 : 0 : driver = container_of(vdev->device.driver, const struct rte_vdev_driver,
183 : : driver);
184 : :
185 [ # # ]: 0 : if (driver->dma_unmap)
186 : 0 : return driver->dma_unmap(vdev, addr, iova, len);
187 : :
188 : : return 0;
189 : : }
190 : :
191 : : static int
192 : 29 : vdev_probe_all_drivers(struct rte_vdev_device *dev)
193 : : {
194 : : const char *name;
195 : : struct rte_vdev_driver *driver;
196 : : enum rte_iova_mode iova_mode;
197 : : int ret;
198 : :
199 [ + - ]: 29 : if (rte_dev_is_probed(&dev->device))
200 : : return -EEXIST;
201 : :
202 : : name = rte_vdev_device_name(dev);
203 : 29 : VDEV_LOG(DEBUG, "Search driver to probe device %s", name);
204 : :
205 [ + - ]: 29 : if (vdev_parse(name, &driver))
206 : : return -1;
207 : :
208 : 29 : iova_mode = rte_eal_iova_mode();
209 [ + + - + ]: 29 : if ((driver->drv_flags & RTE_VDEV_DRV_NEED_IOVA_AS_VA) && (iova_mode == RTE_IOVA_PA)) {
210 : 0 : VDEV_LOG(ERR, "%s requires VA IOVA mode but current mode is PA, not initializing",
211 : : name);
212 : 0 : return -1;
213 : : }
214 : :
215 : 29 : ret = driver->probe(dev);
216 [ + - ]: 29 : if (ret == 0)
217 : 29 : dev->device.driver = &driver->driver;
218 : : return ret;
219 : : }
220 : :
221 : : /* The caller shall be responsible for thread-safe */
222 : : static struct rte_vdev_device *
223 : 49 : find_vdev(const char *name)
224 : : {
225 : : struct rte_vdev_device *dev;
226 : :
227 [ + - ]: 49 : if (!name)
228 : : return NULL;
229 : :
230 [ + + ]: 86 : TAILQ_FOREACH(dev, &vdev_device_list, next) {
231 : : const char *devname = rte_vdev_device_name(dev);
232 : :
233 [ + + ]: 55 : if (!strcmp(devname, name))
234 : 18 : return dev;
235 : : }
236 : :
237 : : return NULL;
238 : : }
239 : :
240 : : static struct rte_devargs *
241 : 20 : alloc_devargs(const char *name, const char *args)
242 : : {
243 : : struct rte_devargs *devargs;
244 : : int ret;
245 : :
246 : 20 : devargs = calloc(1, sizeof(*devargs));
247 [ + - ]: 20 : if (!devargs)
248 : : return NULL;
249 : :
250 : 20 : devargs->bus = &rte_vdev_bus;
251 [ + + ]: 20 : if (args)
252 : 14 : devargs->data = strdup(args);
253 : : else
254 : 6 : devargs->data = strdup("");
255 [ - + ]: 20 : if (devargs->data == NULL) {
256 : 0 : free(devargs);
257 : 0 : return NULL;
258 : : }
259 : 20 : devargs->args = devargs->data;
260 : :
261 [ - + ]: 20 : ret = strlcpy(devargs->name, name, sizeof(devargs->name));
262 [ - + ]: 20 : if (ret < 0 || ret >= (int)sizeof(devargs->name)) {
263 : 0 : rte_devargs_reset(devargs);
264 : 0 : free(devargs);
265 : 0 : return NULL;
266 : : }
267 : :
268 : : return devargs;
269 : : }
270 : :
271 : : static int
272 : 20 : insert_vdev(const char *name, const char *args,
273 : : struct rte_vdev_device **p_dev,
274 : : bool init)
275 : : {
276 : : struct rte_vdev_device *dev;
277 : : struct rte_devargs *devargs;
278 : : int ret;
279 : :
280 [ + - ]: 20 : if (name == NULL)
281 : : return -EINVAL;
282 : :
283 : 20 : devargs = alloc_devargs(name, args);
284 : :
285 [ + - ]: 20 : if (!devargs)
286 : : return -ENOMEM;
287 : :
288 : 20 : dev = calloc(1, sizeof(*dev));
289 [ - + ]: 20 : if (!dev) {
290 : : ret = -ENOMEM;
291 : 0 : goto fail;
292 : : }
293 : :
294 : 20 : dev->device.bus = &rte_vdev_bus;
295 : 20 : dev->device.numa_node = SOCKET_ID_ANY;
296 : :
297 [ - + ]: 20 : if (find_vdev(name)) {
298 : : /*
299 : : * A vdev is expected to have only one port.
300 : : * So there is no reason to try probing again,
301 : : * even with new arguments.
302 : : */
303 : : ret = -EEXIST;
304 : 0 : goto fail;
305 : : }
306 : :
307 [ + + ]: 20 : if (init)
308 : 19 : rte_devargs_insert(&devargs);
309 : 20 : dev->device.devargs = devargs;
310 : 20 : dev->device.name = devargs->name;
311 : 20 : TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
312 : :
313 [ + + ]: 20 : if (p_dev)
314 : 19 : *p_dev = dev;
315 : :
316 : : return 0;
317 : 0 : fail:
318 : 0 : rte_devargs_reset(devargs);
319 : 0 : free(devargs);
320 : 0 : free(dev);
321 : 0 : return ret;
322 : : }
323 : :
324 : : RTE_EXPORT_SYMBOL(rte_vdev_init)
325 : : int
326 : 19 : rte_vdev_init(const char *name, const char *args)
327 : : {
328 : : struct rte_vdev_device *dev;
329 : : int ret;
330 : :
331 : 19 : rte_spinlock_recursive_lock(&vdev_device_list_lock);
332 : 19 : ret = insert_vdev(name, args, &dev, true);
333 [ + - ]: 19 : if (ret == 0) {
334 : 19 : ret = vdev_probe_all_drivers(dev);
335 [ - + ]: 19 : if (ret) {
336 [ # # ]: 0 : if (ret > 0)
337 : 0 : VDEV_LOG(ERR, "no driver found for %s", name);
338 : : /* If fails, remove it from vdev list */
339 [ # # ]: 0 : TAILQ_REMOVE(&vdev_device_list, dev, next);
340 : 0 : rte_devargs_remove(dev->device.devargs);
341 : 0 : free(dev);
342 : : }
343 : : }
344 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
345 : 19 : return ret;
346 : : }
347 : :
348 : : static int
349 [ + - ]: 17 : vdev_remove_driver(struct rte_vdev_device *dev)
350 : : {
351 : : const char *name = rte_vdev_device_name(dev);
352 : : const struct rte_vdev_driver *driver;
353 : :
354 [ - + ]: 17 : if (!dev->device.driver) {
355 : 0 : VDEV_LOG(DEBUG, "no driver attach to device %s", name);
356 : 0 : return 1;
357 : : }
358 : :
359 : 17 : driver = container_of(dev->device.driver, const struct rte_vdev_driver,
360 : : driver);
361 : 17 : return driver->remove(dev);
362 : : }
363 : :
364 : : RTE_EXPORT_SYMBOL(rte_vdev_uninit)
365 : : int
366 : 18 : rte_vdev_uninit(const char *name)
367 : : {
368 : : struct rte_vdev_device *dev;
369 : : int ret;
370 : :
371 [ + - ]: 18 : if (name == NULL)
372 : : return -EINVAL;
373 : :
374 : 18 : rte_spinlock_recursive_lock(&vdev_device_list_lock);
375 : :
376 : 18 : dev = find_vdev(name);
377 [ + + ]: 18 : if (!dev) {
378 : : ret = -ENOENT;
379 : 1 : goto unlock;
380 : : }
381 : :
382 : 17 : ret = vdev_remove_driver(dev);
383 [ - + ]: 17 : if (ret)
384 : 0 : goto unlock;
385 : :
386 [ + + ]: 17 : TAILQ_REMOVE(&vdev_device_list, dev, next);
387 : 17 : rte_devargs_remove(dev->device.devargs);
388 : 17 : free(dev);
389 : :
390 [ + - ]: 18 : unlock:
391 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
392 : : return ret;
393 : : }
394 : :
395 : : struct vdev_param {
396 : : #define VDEV_SCAN_REQ 1
397 : : #define VDEV_SCAN_ONE 2
398 : : #define VDEV_SCAN_REP 3
399 : : int type;
400 : : int num;
401 : : char name[RTE_DEV_NAME_MAX_LEN];
402 : : };
403 : :
404 : : static int vdev_plug(struct rte_device *dev);
405 : :
406 : : /**
407 : : * This function works as the action for both primary and secondary process
408 : : * for static vdev discovery when a secondary process is booting.
409 : : *
410 : : * step 1, secondary process sends a sync request to ask for vdev in primary;
411 : : * step 2, primary process receives the request, and send vdevs one by one;
412 : : * step 3, primary process sends back reply, which indicates how many vdevs
413 : : * are sent.
414 : : */
415 : : static int
416 [ + + - ]: 27 : vdev_action(const struct rte_mp_msg *mp_msg, const void *peer)
417 : : {
418 : : struct rte_vdev_device *dev;
419 : : struct rte_mp_msg mp_resp;
420 : : struct vdev_param *ou = (struct vdev_param *)&mp_resp.param;
421 : : const struct vdev_param *in = (const struct vdev_param *)mp_msg->param;
422 : : const char *devname;
423 : : int num;
424 : : int ret;
425 : :
426 : : strlcpy(mp_resp.name, VDEV_MP_KEY, sizeof(mp_resp.name));
427 : 27 : mp_resp.len_param = sizeof(*ou);
428 : 27 : mp_resp.num_fds = 0;
429 : :
430 [ + + - ]: 27 : switch (in->type) {
431 : 26 : case VDEV_SCAN_REQ:
432 : 26 : ou->type = VDEV_SCAN_ONE;
433 : 26 : ou->num = 1;
434 : : num = 0;
435 : :
436 : 26 : rte_spinlock_recursive_lock(&vdev_device_list_lock);
437 [ + + ]: 27 : TAILQ_FOREACH(dev, &vdev_device_list, next) {
438 : : devname = rte_vdev_device_name(dev);
439 [ - + ]: 1 : if (strlen(devname) == 0) {
440 : 0 : VDEV_LOG(INFO, "vdev with no name is not sent");
441 : 0 : continue;
442 : : }
443 : 1 : VDEV_LOG(INFO, "send vdev, %s", devname);
444 : : strlcpy(ou->name, devname, RTE_DEV_NAME_MAX_LEN);
445 [ - + ]: 1 : if (rte_mp_sendmsg(&mp_resp) < 0)
446 : 0 : VDEV_LOG(ERR, "send vdev, %s, failed, %s",
447 : : devname, strerror(rte_errno));
448 : 1 : num++;
449 : : }
450 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
451 : :
452 : 26 : ou->type = VDEV_SCAN_REP;
453 : 26 : ou->num = num;
454 [ - + ]: 26 : if (rte_mp_reply(&mp_resp, peer) < 0)
455 : 0 : VDEV_LOG(ERR, "Failed to reply a scan request");
456 : : break;
457 : 1 : case VDEV_SCAN_ONE:
458 : 1 : VDEV_LOG(INFO, "receive vdev, %s", in->name);
459 : 1 : ret = insert_vdev(in->name, NULL, NULL, false);
460 [ - + ]: 1 : if (ret == -EEXIST)
461 : 0 : VDEV_LOG(DEBUG, "device already exist, %s", in->name);
462 [ - + ]: 1 : else if (ret < 0)
463 : 0 : VDEV_LOG(ERR, "failed to add vdev, %s", in->name);
464 : : break;
465 : 0 : default:
466 : 0 : VDEV_LOG(ERR, "vdev cannot recognize this message");
467 : : }
468 : :
469 : 27 : return 0;
470 : : }
471 : :
472 : : static int
473 : 185 : vdev_scan(void)
474 : : {
475 : : struct rte_vdev_device *dev;
476 : : struct rte_devargs *devargs;
477 : : struct vdev_custom_scan *custom_scan;
478 : :
479 [ + + ]: 185 : if (rte_mp_action_register(VDEV_MP_KEY, vdev_action) < 0 &&
480 [ + - ]: 7 : rte_errno != EEXIST) {
481 : : /* for primary, unsupported IPC is not an error */
482 [ + - ]: 7 : if (rte_eal_process_type() == RTE_PROC_PRIMARY &&
483 [ + - ]: 7 : rte_errno == ENOTSUP)
484 : 7 : goto scan;
485 : 0 : VDEV_LOG(ERR, "Failed to add vdev mp action");
486 : 0 : return -1;
487 : : }
488 : :
489 [ + + ]: 178 : if (rte_eal_process_type() == RTE_PROC_SECONDARY) {
490 : : struct rte_mp_msg mp_req, *mp_rep;
491 : : struct rte_mp_reply mp_reply;
492 : 27 : struct timespec ts = {.tv_sec = 5, .tv_nsec = 0};
493 : : struct vdev_param *req = (struct vdev_param *)mp_req.param;
494 : : struct vdev_param *resp;
495 : :
496 : : strlcpy(mp_req.name, VDEV_MP_KEY, sizeof(mp_req.name));
497 : 27 : mp_req.len_param = sizeof(*req);
498 : 27 : mp_req.num_fds = 0;
499 : 27 : req->type = VDEV_SCAN_REQ;
500 [ + + ]: 27 : if (rte_mp_request_sync(&mp_req, &mp_reply, &ts) == 0 &&
501 [ + - ]: 26 : mp_reply.nb_received == 1) {
502 : 26 : mp_rep = &mp_reply.msgs[0];
503 : : resp = (struct vdev_param *)mp_rep->param;
504 : 26 : VDEV_LOG(INFO, "Received %d vdevs", resp->num);
505 : 26 : free(mp_reply.msgs);
506 : : } else
507 : 1 : VDEV_LOG(ERR, "Failed to request vdev from primary");
508 : :
509 : : /* Fall through to allow private vdevs in secondary process */
510 : : }
511 : :
512 : 185 : scan:
513 : : /* call custom scan callbacks if any */
514 : : rte_spinlock_lock(&vdev_custom_scan_lock);
515 [ - + ]: 185 : TAILQ_FOREACH(custom_scan, &vdev_custom_scans, next) {
516 [ # # ]: 0 : if (custom_scan->callback != NULL)
517 : : /*
518 : : * the callback should update devargs list
519 : : * by calling rte_devargs_insert() with
520 : : * devargs.bus = rte_bus_find_by_name("vdev");
521 : : * devargs.type = RTE_DEVTYPE_VIRTUAL;
522 : : * devargs.policy = RTE_DEV_ALLOWED;
523 : : */
524 : 0 : custom_scan->callback(custom_scan->user_arg);
525 : : }
526 : : rte_spinlock_unlock(&vdev_custom_scan_lock);
527 : :
528 : : /* for virtual devices we scan the devargs_list populated via cmdline */
529 [ + + ]: 196 : RTE_EAL_DEVARGS_FOREACH("vdev", devargs) {
530 : :
531 : 11 : dev = calloc(1, sizeof(*dev));
532 [ + - ]: 11 : if (!dev)
533 : : return -1;
534 : :
535 : 11 : rte_spinlock_recursive_lock(&vdev_device_list_lock);
536 : :
537 [ + + ]: 11 : if (find_vdev(devargs->name)) {
538 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
539 : 1 : free(dev);
540 : 1 : continue;
541 : : }
542 : :
543 : 10 : dev->device.bus = &rte_vdev_bus;
544 : 10 : dev->device.devargs = devargs;
545 : 10 : dev->device.numa_node = SOCKET_ID_ANY;
546 : 10 : dev->device.name = devargs->name;
547 : :
548 [ + - ]: 10 : TAILQ_INSERT_TAIL(&vdev_device_list, dev, next);
549 : :
550 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
551 : : }
552 : :
553 : : return 0;
554 : : }
555 : :
556 : : static int
557 : 180 : vdev_probe(void)
558 : : {
559 : : struct rte_vdev_device *dev;
560 : : int r, ret = 0;
561 : :
562 : : /* call the init function for each virtual device */
563 [ + + ]: 190 : TAILQ_FOREACH(dev, &vdev_device_list, next) {
564 : : /* we don't use the vdev lock here, as it's only used in DPDK
565 : : * initialization; and we don't want to hold such a lock when
566 : : * we call each driver probe.
567 : : */
568 : :
569 : 10 : r = vdev_probe_all_drivers(dev);
570 [ - + ]: 10 : if (r != 0) {
571 [ # # ]: 0 : if (r == -EEXIST)
572 : 0 : continue;
573 : 0 : VDEV_LOG(ERR, "failed to initialize %s device",
574 : : rte_vdev_device_name(dev));
575 : : ret = -1;
576 : : }
577 : : }
578 : :
579 : 180 : return ret;
580 : : }
581 : :
582 : : static int
583 : 252 : vdev_cleanup(void)
584 : : {
585 : : struct rte_vdev_device *dev, *tmp_dev;
586 : : int error = 0;
587 : :
588 [ + + ]: 265 : RTE_TAILQ_FOREACH_SAFE(dev, &vdev_device_list, next, tmp_dev) {
589 : : const struct rte_vdev_driver *drv;
590 : : int ret = 0;
591 : :
592 [ + + ]: 13 : if (dev->device.driver == NULL)
593 : 1 : goto free;
594 : :
595 : 12 : drv = container_of(dev->device.driver, const struct rte_vdev_driver, driver);
596 : :
597 [ - + ]: 12 : if (drv->remove == NULL)
598 : 0 : goto free;
599 : :
600 : 12 : ret = drv->remove(dev);
601 [ - + ]: 12 : if (ret < 0)
602 : : error = -1;
603 : :
604 : : dev->device.driver = NULL;
605 : 13 : free:
606 : 13 : free(dev);
607 : : }
608 : :
609 : 252 : return error;
610 : : }
611 : :
612 : : struct rte_device *
613 : 10 : rte_vdev_find_device(const struct rte_device *start, rte_dev_cmp_t cmp,
614 : : const void *data)
615 : : {
616 : : const struct rte_vdev_device *vstart;
617 : : struct rte_vdev_device *dev;
618 : :
619 : 10 : rte_spinlock_recursive_lock(&vdev_device_list_lock);
620 [ + + ]: 10 : if (start != NULL) {
621 : 2 : vstart = RTE_DEV_TO_VDEV_CONST(start);
622 : 2 : dev = TAILQ_NEXT(vstart, next);
623 : : } else {
624 : 8 : dev = TAILQ_FIRST(&vdev_device_list);
625 : : }
626 [ + + ]: 14 : while (dev != NULL) {
627 [ + + ]: 12 : if (cmp(&dev->device, data) == 0)
628 : : break;
629 : 4 : dev = TAILQ_NEXT(dev, next);
630 : : }
631 : : rte_spinlock_recursive_unlock(&vdev_device_list_lock);
632 : :
633 [ + + ]: 10 : return dev ? &dev->device : NULL;
634 : : }
635 : :
636 : : static int
637 : 0 : vdev_plug(struct rte_device *dev)
638 : : {
639 : 0 : return vdev_probe_all_drivers(RTE_DEV_TO_VDEV(dev));
640 : : }
641 : :
642 : : static int
643 : 0 : vdev_unplug(struct rte_device *dev)
644 : : {
645 : 0 : return rte_vdev_uninit(dev->name);
646 : : }
647 : :
648 : : static enum rte_iova_mode
649 : 185 : vdev_get_iommu_class(void)
650 : : {
651 : : const char *name;
652 : : struct rte_vdev_device *dev;
653 : : struct rte_vdev_driver *driver;
654 : :
655 [ + + ]: 192 : TAILQ_FOREACH(dev, &vdev_device_list, next) {
656 : : name = rte_vdev_device_name(dev);
657 [ - + ]: 8 : if (vdev_parse(name, &driver))
658 : 0 : continue;
659 : :
660 [ + + ]: 8 : if (driver->drv_flags & RTE_VDEV_DRV_NEED_IOVA_AS_VA)
661 : : return RTE_IOVA_VA;
662 : : }
663 : :
664 : : return RTE_IOVA_DC;
665 : : }
666 : :
667 : : static struct rte_bus rte_vdev_bus = {
668 : : .scan = vdev_scan,
669 : : .probe = vdev_probe,
670 : : .cleanup = vdev_cleanup,
671 : : .find_device = rte_vdev_find_device,
672 : : .plug = vdev_plug,
673 : : .unplug = vdev_unplug,
674 : : .parse = vdev_parse,
675 : : .dma_map = vdev_dma_map,
676 : : .dma_unmap = vdev_dma_unmap,
677 : : .get_iommu_class = vdev_get_iommu_class,
678 : : .dev_iterate = rte_vdev_dev_iterate,
679 : : };
680 : :
681 : 252 : RTE_REGISTER_BUS(vdev, rte_vdev_bus);
682 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(vdev_logtype_bus, NOTICE);
|