Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(C) 2023 Marvell.
3 : : */
4 : :
5 : : #include <dirent.h>
6 : : #include <inttypes.h>
7 : : #include <stdlib.h>
8 : : #include <string.h>
9 : : #include <sys/ioctl.h>
10 : : #include <sys/mman.h>
11 : : #include <sys/queue.h>
12 : : #include <unistd.h>
13 : :
14 : : #include <bus_driver.h>
15 : : #include <bus_platform_driver.h>
16 : : #include <eal_filesystem.h>
17 : : #include <rte_bus.h>
18 : : #include <rte_devargs.h>
19 : : #include <rte_errno.h>
20 : : #include <rte_log.h>
21 : : #include <rte_memory.h>
22 : : #include <rte_string_fns.h>
23 : : #include <rte_vfio.h>
24 : :
25 : : #include "private.h"
26 : :
27 : : #ifdef VFIO_PRESENT
28 : :
29 : : #define PLATFORM_BUS_DEVICES_PATH "/sys/bus/platform/devices"
30 : :
31 : : void
32 : 0 : rte_platform_register(struct rte_platform_driver *pdrv)
33 : : {
34 : 0 : TAILQ_INSERT_TAIL(&platform_bus.driver_list, pdrv, next);
35 : 0 : }
36 : :
37 : : void
38 : 0 : rte_platform_unregister(struct rte_platform_driver *pdrv)
39 : : {
40 [ # # ]: 0 : TAILQ_REMOVE(&platform_bus.driver_list, pdrv, next);
41 : 0 : }
42 : :
43 : : static struct rte_devargs *
44 : 2405 : dev_devargs(const char *dev_name)
45 : : {
46 : : struct rte_devargs *devargs;
47 : :
48 [ - + ]: 2405 : RTE_EAL_DEVARGS_FOREACH("platform", devargs) {
49 [ # # ]: 0 : if (!strcmp(devargs->name, dev_name))
50 : 0 : return devargs;
51 : : }
52 : :
53 : : return NULL;
54 : : }
55 : :
56 : : static bool
57 : 2405 : dev_allowed(const char *dev_name)
58 : : {
59 : : struct rte_devargs *devargs;
60 : :
61 : 2405 : devargs = dev_devargs(dev_name);
62 [ - + ]: 2405 : if (devargs == NULL)
63 : : return true;
64 : :
65 [ # # # ]: 0 : switch (platform_bus.bus.conf.scan_mode) {
66 : 0 : case RTE_BUS_SCAN_UNDEFINED:
67 : : case RTE_BUS_SCAN_ALLOWLIST:
68 : 0 : if (devargs->policy == RTE_DEV_ALLOWED)
69 : : return true;
70 : : break;
71 : 0 : case RTE_BUS_SCAN_BLOCKLIST:
72 [ # # ]: 0 : if (devargs->policy == RTE_DEV_BLOCKED)
73 : 0 : return false;
74 : : break;
75 : : }
76 : :
77 : : return true;
78 : : }
79 : :
80 : : static int
81 : 0 : dev_add(const char *dev_name)
82 : : {
83 : : struct rte_platform_device *pdev, *tmp;
84 : : char path[PATH_MAX];
85 : : unsigned long val;
86 : :
87 : 0 : pdev = calloc(1, sizeof(*pdev));
88 [ # # ]: 0 : if (pdev == NULL)
89 : : return -ENOMEM;
90 : :
91 : 0 : rte_strscpy(pdev->name, dev_name, sizeof(pdev->name));
92 : 0 : pdev->device.name = pdev->name;
93 : 0 : pdev->device.devargs = dev_devargs(dev_name);
94 : 0 : pdev->device.bus = &platform_bus.bus;
95 : : snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/numa_node", dev_name);
96 [ # # ]: 0 : pdev->device.numa_node = eal_parse_sysfs_value(path, &val) ? rte_socket_id() : val;
97 : :
98 [ # # ]: 0 : FOREACH_DEVICE_ON_PLATFORM_BUS(tmp) {
99 [ # # ]: 0 : if (!strcmp(tmp->name, pdev->name)) {
100 : 0 : PLATFORM_LOG_LINE(INFO, "device %s already added", pdev->name);
101 : :
102 [ # # ]: 0 : if (tmp->device.devargs != pdev->device.devargs)
103 : 0 : rte_devargs_remove(pdev->device.devargs);
104 : :
105 : 0 : free(pdev);
106 : 0 : return -EEXIST;
107 : : }
108 : : }
109 : :
110 [ # # ]: 0 : TAILQ_INSERT_HEAD(&platform_bus.device_list, pdev, next);
111 : :
112 : 0 : PLATFORM_LOG_LINE(INFO, "adding device %s to the list", dev_name);
113 : :
114 : 0 : return 0;
115 : : }
116 : :
117 : : static char *
118 : 2405 : dev_kernel_driver_name(const char *dev_name)
119 : : {
120 : 2405 : char path[PATH_MAX], buf[BUFSIZ] = { };
121 : : char *kdrv;
122 : : int ret;
123 : :
124 : : snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/driver", dev_name);
125 : : /* save space for NUL */
126 : 2405 : ret = readlink(path, buf, sizeof(buf) - 1);
127 [ + + ]: 2405 : if (ret <= 0)
128 : : return NULL;
129 : :
130 : : /* last token is kernel driver name */
131 : 925 : kdrv = strrchr(buf, '/');
132 [ + - ]: 925 : if (kdrv != NULL)
133 : 925 : return strdup(kdrv + 1);
134 : :
135 : : return NULL;
136 : : }
137 : :
138 : : static bool
139 : 2405 : dev_is_bound_vfio_platform(const char *dev_name)
140 : : {
141 : : char *kdrv;
142 : : int ret;
143 : :
144 : 2405 : kdrv = dev_kernel_driver_name(dev_name);
145 [ + + ]: 2405 : if (!kdrv)
146 : : return false;
147 : :
148 : 925 : ret = strcmp(kdrv, "vfio-platform");
149 : 925 : free(kdrv);
150 : :
151 : 925 : return ret == 0;
152 : : }
153 : :
154 : : static int
155 : 185 : platform_bus_scan(void)
156 : : {
157 : : const struct dirent *ent;
158 : : const char *dev_name;
159 : : int ret = 0;
160 : : DIR *dp;
161 : :
162 : 185 : dp = opendir(PLATFORM_BUS_DEVICES_PATH);
163 [ - + ]: 185 : if (dp == NULL) {
164 : 0 : PLATFORM_LOG_LINE(INFO, "failed to open %s", PLATFORM_BUS_DEVICES_PATH);
165 : 0 : return -errno;
166 : : }
167 : :
168 [ + + ]: 2960 : while ((ent = readdir(dp))) {
169 : 2775 : dev_name = ent->d_name;
170 [ + + ]: 2775 : if (dev_name[0] == '.')
171 : 370 : continue;
172 : :
173 [ - + ]: 2405 : if (!dev_allowed(dev_name))
174 : 0 : continue;
175 : :
176 [ + - ]: 2405 : if (!dev_is_bound_vfio_platform(dev_name))
177 : 2405 : continue;
178 : :
179 : 0 : ret = dev_add(dev_name);
180 [ # # ]: 0 : if (ret)
181 : : break;
182 : : }
183 : :
184 : 185 : closedir(dp);
185 : :
186 : 185 : return ret;
187 : : }
188 : :
189 : : static int
190 : 0 : device_map_resource_offset(struct rte_platform_device *pdev, struct rte_platform_resource *res,
191 : : size_t offset)
192 : : {
193 : 0 : res->mem.addr = mmap(NULL, res->mem.len, PROT_READ | PROT_WRITE, MAP_SHARED, pdev->dev_fd,
194 : : offset);
195 [ # # ]: 0 : if (res->mem.addr == MAP_FAILED)
196 : 0 : return -errno;
197 : :
198 : 0 : PLATFORM_LOG_LINE(DEBUG, "adding resource va = %p len = %"PRIu64" name = %s", res->mem.addr,
199 : : res->mem.len, res->name);
200 : :
201 : 0 : return 0;
202 : : }
203 : :
204 : : static void
205 : 0 : device_unmap_resources(struct rte_platform_device *pdev)
206 : : {
207 : : struct rte_platform_resource *res;
208 : : unsigned int i;
209 : :
210 [ # # ]: 0 : for (i = 0; i < pdev->num_resource; i++) {
211 : 0 : res = &pdev->resource[i];
212 : 0 : munmap(res->mem.addr, res->mem.len);
213 : 0 : free(res->name);
214 : : }
215 : :
216 : 0 : free(pdev->resource);
217 : 0 : pdev->resource = NULL;
218 : 0 : pdev->num_resource = 0;
219 : 0 : }
220 : :
221 : : static int
222 : 0 : read_sysfs_string(const char *path, char *buf, size_t size)
223 : : {
224 : : FILE *f;
225 : : char *p;
226 : :
227 : 0 : f = fopen(path, "r");
228 [ # # ]: 0 : if (f == NULL)
229 : 0 : return -errno;
230 : :
231 [ # # # # ]: 0 : if (fgets(buf, size, f) == NULL) {
232 : 0 : fclose(f);
233 : 0 : return -ENODATA;
234 : : }
235 : :
236 : 0 : fclose(f);
237 : :
238 : 0 : p = strrchr(buf, '\n');
239 [ # # ]: 0 : if (p != NULL)
240 : 0 : *p = '\0';
241 : :
242 : : return 0;
243 : : }
244 : :
245 : : static char *
246 : 0 : of_resource_name(const char *dev_name, int index)
247 : : {
248 : 0 : char path[PATH_MAX], buf[BUFSIZ] = { };
249 : : int num = 0, ret;
250 : : char *name;
251 : :
252 : : snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/of_node/reg-names", dev_name);
253 : 0 : ret = read_sysfs_string(path, buf, sizeof(buf) - 1);
254 [ # # ]: 0 : if (ret)
255 : : return NULL;
256 : :
257 [ # # ]: 0 : for (name = buf; *name != 0; name += strlen(name) + 1) {
258 [ # # ]: 0 : if (num++ != index)
259 : : continue;
260 : 0 : return strdup(name);
261 : : }
262 : :
263 : : return NULL;
264 : : }
265 : :
266 : : static int
267 : 0 : device_map_resources(struct rte_platform_device *pdev, unsigned int num)
268 : : {
269 : : struct rte_platform_resource *res;
270 : : unsigned int i;
271 : : int ret;
272 : :
273 [ # # ]: 0 : if (num == 0) {
274 : 0 : PLATFORM_LOG_LINE(WARNING, "device %s has no resources", pdev->name);
275 : 0 : return 0;
276 : : }
277 : :
278 : 0 : pdev->resource = calloc(num, sizeof(*pdev->resource));
279 [ # # ]: 0 : if (pdev->resource == NULL)
280 : : return -ENOMEM;
281 : :
282 [ # # ]: 0 : for (i = 0; i < num; i++) {
283 : 0 : struct vfio_region_info reg_info = {
284 : : .argsz = sizeof(reg_info),
285 : : .index = i,
286 : : };
287 : :
288 : 0 : ret = ioctl(pdev->dev_fd, VFIO_DEVICE_GET_REGION_INFO, ®_info);
289 [ # # ]: 0 : if (ret) {
290 : 0 : PLATFORM_LOG_LINE(ERR, "failed to get region info at %d", i);
291 : 0 : ret = -errno;
292 : 0 : goto out;
293 : : }
294 : :
295 : 0 : res = &pdev->resource[i];
296 : 0 : res->name = of_resource_name(pdev->name, reg_info.index);
297 : 0 : res->mem.len = reg_info.size;
298 : 0 : ret = device_map_resource_offset(pdev, res, reg_info.offset);
299 [ # # ]: 0 : if (ret) {
300 : 0 : PLATFORM_LOG_LINE(ERR, "failed to ioremap resource at %d", i);
301 : 0 : goto out;
302 : : }
303 : :
304 : 0 : pdev->num_resource++;
305 : : }
306 : :
307 : : return 0;
308 : : out:
309 : 0 : device_unmap_resources(pdev);
310 : :
311 : 0 : return ret;
312 : : }
313 : :
314 : : static void
315 : 0 : device_cleanup(struct rte_platform_device *pdev)
316 : : {
317 : 0 : device_unmap_resources(pdev);
318 : 0 : rte_vfio_release_device(PLATFORM_BUS_DEVICES_PATH, pdev->name, pdev->dev_fd);
319 : 0 : }
320 : :
321 : : static int
322 : 0 : device_setup(struct rte_platform_device *pdev)
323 : : {
324 : 0 : struct vfio_device_info dev_info = { .argsz = sizeof(dev_info), };
325 : 0 : const char *name = pdev->name;
326 : : int ret;
327 : :
328 : 0 : ret = rte_vfio_setup_device(PLATFORM_BUS_DEVICES_PATH, name, &pdev->dev_fd, &dev_info);
329 [ # # ]: 0 : if (ret) {
330 : 0 : PLATFORM_LOG_LINE(ERR, "failed to setup %s", name);
331 : 0 : return -ENODEV;
332 : : }
333 : :
334 : : /* This is an extra check to confirm that platform device was initialized
335 : : * by a kernel vfio-platform driver. On kernels that predate vfio-platform
336 : : * driver this flag obviously does not exist. In such scenarios this
337 : : * check needs to be removed otherwise compilation fails.
338 : : *
339 : : * Now, on such old kernels code will never reach here because
340 : : * there is another check much earlier which verifies whether
341 : : * device has been bound to vfio-platform driver.
342 : : */
343 : : #ifdef VFIO_DEVICE_FLAGS_PLATFORM
344 [ # # ]: 0 : if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PLATFORM)) {
345 : 0 : PLATFORM_LOG_LINE(ERR, "device not backed by vfio-platform");
346 : : ret = -ENOTSUP;
347 : 0 : goto out;
348 : : }
349 : : #endif
350 : :
351 : 0 : ret = device_map_resources(pdev, dev_info.num_regions);
352 [ # # ]: 0 : if (ret) {
353 : 0 : PLATFORM_LOG_LINE(ERR, "failed to setup platform resources");
354 : 0 : goto out;
355 : : }
356 : :
357 : : return 0;
358 : 0 : out:
359 : 0 : device_cleanup(pdev);
360 : :
361 : 0 : return ret;
362 : : }
363 : :
364 : : static int
365 : 0 : driver_call_probe(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev)
366 : : {
367 : : int ret;
368 : :
369 [ # # ]: 0 : if (rte_dev_is_probed(&pdev->device))
370 : : return -EBUSY;
371 : :
372 [ # # ]: 0 : if (pdrv->probe != NULL) {
373 : 0 : pdev->driver = pdrv;
374 : 0 : ret = pdrv->probe(pdev);
375 [ # # ]: 0 : if (ret)
376 : : return ret;
377 : : }
378 : :
379 : 0 : pdev->device.driver = &pdrv->driver;
380 : :
381 : 0 : return 0;
382 : : }
383 : :
384 : : static int
385 : 0 : driver_probe_device(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev)
386 : : {
387 : : enum rte_iova_mode iova_mode;
388 : : int ret;
389 : :
390 : 0 : iova_mode = rte_eal_iova_mode();
391 [ # # # # ]: 0 : if (pdrv->drv_flags & RTE_PLATFORM_DRV_NEED_IOVA_AS_VA && iova_mode != RTE_IOVA_VA) {
392 : 0 : PLATFORM_LOG_LINE(ERR, "driver %s expects VA IOVA mode but current mode is PA",
393 : : pdrv->driver.name);
394 : 0 : return -EINVAL;
395 : : }
396 : :
397 : 0 : ret = device_setup(pdev);
398 [ # # ]: 0 : if (ret)
399 : : return ret;
400 : :
401 : 0 : ret = driver_call_probe(pdrv, pdev);
402 [ # # ]: 0 : if (ret)
403 : 0 : device_cleanup(pdev);
404 : :
405 : : return ret;
406 : : }
407 : :
408 : : static bool
409 : 0 : driver_match_device(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev)
410 : : {
411 : : bool match = false;
412 : : char *kdrv;
413 : :
414 : 0 : kdrv = dev_kernel_driver_name(pdev->name);
415 [ # # ]: 0 : if (!kdrv)
416 : : return false;
417 : :
418 : : /* match by driver name */
419 [ # # ]: 0 : if (!strcmp(kdrv, pdrv->driver.name)) {
420 : : match = true;
421 : 0 : goto out;
422 : : }
423 : :
424 : : /* match by driver alias */
425 [ # # # # ]: 0 : if (pdrv->driver.alias != NULL && !strcmp(kdrv, pdrv->driver.alias)) {
426 : : match = true;
427 : 0 : goto out;
428 : : }
429 : :
430 : : /* match by device name */
431 [ # # ]: 0 : if (!strcmp(pdev->name, pdrv->driver.name))
432 : : match = true;
433 : :
434 : 0 : out:
435 : 0 : free(kdrv);
436 : :
437 : 0 : return match;
438 : : }
439 : :
440 : : static int
441 : 0 : device_attach(struct rte_platform_device *pdev)
442 : : {
443 : : struct rte_platform_driver *pdrv;
444 : :
445 [ # # ]: 0 : FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) {
446 [ # # ]: 0 : if (driver_match_device(pdrv, pdev))
447 : : break;
448 : : }
449 : :
450 [ # # ]: 0 : if (pdrv == NULL)
451 : : return -ENODEV;
452 : :
453 : 0 : return driver_probe_device(pdrv, pdev);
454 : : }
455 : :
456 : : static int
457 : 180 : platform_bus_probe(void)
458 : : {
459 : : struct rte_platform_device *pdev;
460 : : int ret;
461 : :
462 [ - + ]: 180 : FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) {
463 : 0 : ret = device_attach(pdev);
464 [ # # ]: 0 : if (ret == -EBUSY) {
465 : 0 : PLATFORM_LOG_LINE(DEBUG, "device %s already probed", pdev->name);
466 : 0 : continue;
467 : : }
468 [ # # ]: 0 : if (ret)
469 : 0 : PLATFORM_LOG_LINE(ERR, "failed to probe %s", pdev->name);
470 : : }
471 : :
472 : 180 : return 0;
473 : : }
474 : :
475 : : static struct rte_device *
476 : 0 : platform_bus_find_device(const struct rte_device *start, rte_dev_cmp_t cmp, const void *data)
477 : : {
478 : : struct rte_platform_device *pdev;
479 : :
480 [ # # ]: 0 : pdev = start ? RTE_TAILQ_NEXT(RTE_DEV_TO_PLATFORM_DEV_CONST(start), next) :
481 : : RTE_TAILQ_FIRST(&platform_bus.device_list);
482 [ # # ]: 0 : while (pdev) {
483 [ # # ]: 0 : if (cmp(&pdev->device, data) == 0)
484 : 0 : return &pdev->device;
485 : :
486 : 0 : pdev = RTE_TAILQ_NEXT(pdev, next);
487 : : }
488 : :
489 : : return NULL;
490 : : }
491 : :
492 : : static int
493 : 0 : platform_bus_plug(struct rte_device *dev)
494 : : {
495 : : struct rte_platform_device *pdev;
496 : :
497 [ # # ]: 0 : if (!dev_allowed(dev->name))
498 : : return -EPERM;
499 : :
500 [ # # ]: 0 : if (!dev_is_bound_vfio_platform(dev->name))
501 : : return -EPERM;
502 : :
503 : 0 : pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
504 [ # # ]: 0 : if (pdev == NULL)
505 : : return -EINVAL;
506 : :
507 : 0 : return device_attach(pdev);
508 : : }
509 : :
510 : : static void
511 : 0 : device_release_driver(struct rte_platform_device *pdev)
512 : : {
513 : : struct rte_platform_driver *pdrv;
514 : : int ret;
515 : :
516 : 0 : pdrv = pdev->driver;
517 [ # # # # ]: 0 : if (pdrv != NULL && pdrv->remove != NULL) {
518 : 0 : ret = pdrv->remove(pdev);
519 [ # # ]: 0 : if (ret)
520 : 0 : PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
521 : : }
522 : :
523 : 0 : pdev->device.driver = NULL;
524 : 0 : pdev->driver = NULL;
525 : 0 : }
526 : :
527 : : static int
528 : 0 : platform_bus_unplug(struct rte_device *dev)
529 : : {
530 : : struct rte_platform_device *pdev;
531 : :
532 : 0 : pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
533 [ # # ]: 0 : if (pdev == NULL)
534 : : return -EINVAL;
535 : :
536 : 0 : device_release_driver(pdev);
537 : 0 : device_cleanup(pdev);
538 : 0 : rte_devargs_remove(pdev->device.devargs);
539 : 0 : free(pdev);
540 : :
541 : 0 : return 0;
542 : : }
543 : :
544 : : static int
545 : 28 : platform_bus_parse(const char *name, void *addr)
546 : : {
547 : 28 : struct rte_platform_device pdev = { };
548 : : struct rte_platform_driver *pdrv;
549 : : const char **out = addr;
550 : :
551 : 28 : rte_strscpy(pdev.name, name, sizeof(pdev.name));
552 : :
553 [ - + ]: 28 : FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) {
554 [ # # ]: 0 : if (driver_match_device(pdrv, &pdev))
555 : : break;
556 : : }
557 : :
558 [ - + ]: 28 : if (pdrv != NULL && addr != NULL)
559 : 0 : *out = name;
560 : :
561 [ + - ]: 28 : return pdrv != NULL ? 0 : -ENODEV;
562 : : }
563 : :
564 : : static int
565 : 0 : platform_bus_dma_map(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
566 : : {
567 : : struct rte_platform_device *pdev;
568 : :
569 : 0 : pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
570 [ # # # # ]: 0 : if (pdev == NULL || pdev->driver == NULL) {
571 : 0 : rte_errno = EINVAL;
572 : 0 : return -1;
573 : : }
574 : :
575 [ # # ]: 0 : if (pdev->driver->dma_map != NULL)
576 : 0 : return pdev->driver->dma_map(pdev, addr, iova, len);
577 : :
578 : 0 : return rte_vfio_container_dma_map(RTE_VFIO_DEFAULT_CONTAINER_FD, (uint64_t)addr, iova, len);
579 : : }
580 : :
581 : : static int
582 : 0 : platform_bus_dma_unmap(struct rte_device *dev, void *addr, uint64_t iova, size_t len)
583 : : {
584 : : struct rte_platform_device *pdev;
585 : :
586 : 0 : pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
587 [ # # # # ]: 0 : if (pdev == NULL || pdev->driver == NULL) {
588 : 0 : rte_errno = EINVAL;
589 : 0 : return -1;
590 : : }
591 : :
592 [ # # ]: 0 : if (pdev->driver->dma_unmap != NULL)
593 : 0 : return pdev->driver->dma_unmap(pdev, addr, iova, len);
594 : :
595 : 0 : return rte_vfio_container_dma_unmap(RTE_VFIO_DEFAULT_CONTAINER_FD, (uint64_t)addr, iova,
596 : : len);
597 : : }
598 : :
599 : : static enum rte_iova_mode
600 : 185 : platform_bus_get_iommu_class(void)
601 : : {
602 : : struct rte_platform_driver *pdrv;
603 : : struct rte_platform_device *pdev;
604 : :
605 [ - + ]: 185 : FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) {
606 : 0 : pdrv = pdev->driver;
607 [ # # # # ]: 0 : if (pdrv != NULL && pdrv->drv_flags & RTE_PLATFORM_DRV_NEED_IOVA_AS_VA)
608 : : return RTE_IOVA_VA;
609 : : }
610 : :
611 : : return RTE_IOVA_DC;
612 : : }
613 : :
614 : : static int
615 : 252 : platform_bus_cleanup(void)
616 : : {
617 : : struct rte_platform_device *pdev, *tmp;
618 : :
619 [ - + ]: 252 : RTE_TAILQ_FOREACH_SAFE(pdev, &platform_bus.device_list, next, tmp) {
620 [ # # ]: 0 : TAILQ_REMOVE(&platform_bus.device_list, pdev, next);
621 : 0 : platform_bus_unplug(&pdev->device);
622 : : }
623 : :
624 : 252 : return 0;
625 : : }
626 : :
627 : : struct rte_platform_bus platform_bus = {
628 : : .bus = {
629 : : .scan = platform_bus_scan,
630 : : .probe = platform_bus_probe,
631 : : .find_device = platform_bus_find_device,
632 : : .plug = platform_bus_plug,
633 : : .unplug = platform_bus_unplug,
634 : : .parse = platform_bus_parse,
635 : : .dma_map = platform_bus_dma_map,
636 : : .dma_unmap = platform_bus_dma_unmap,
637 : : .get_iommu_class = platform_bus_get_iommu_class,
638 : : .dev_iterate = platform_bus_dev_iterate,
639 : : .cleanup = platform_bus_cleanup,
640 : : },
641 : : .device_list = TAILQ_HEAD_INITIALIZER(platform_bus.device_list),
642 : : .driver_list = TAILQ_HEAD_INITIALIZER(platform_bus.driver_list),
643 : : };
644 : :
645 : 252 : RTE_REGISTER_BUS(platform, platform_bus.bus);
646 [ - + ]: 252 : RTE_LOG_REGISTER_DEFAULT(platform_bus_logtype, NOTICE);
647 : :
648 : : #endif /* VFIO_PRESENT */
|