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