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