xref: /dpdk/drivers/bus/platform/platform.c (revision e99981af34632ecce3bac82d05db97b08308f9b5)
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 rte_platform_register(struct rte_platform_driver *pdrv)
33 {
34 	TAILQ_INSERT_TAIL(&platform_bus.driver_list, pdrv, next);
35 }
36 
37 void
38 rte_platform_unregister(struct rte_platform_driver *pdrv)
39 {
40 	TAILQ_REMOVE(&platform_bus.driver_list, pdrv, next);
41 }
42 
43 static struct rte_devargs *
44 dev_devargs(const char *dev_name)
45 {
46 	struct rte_devargs *devargs;
47 
48 	RTE_EAL_DEVARGS_FOREACH("platform", devargs) {
49 		if (!strcmp(devargs->name, dev_name))
50 			return devargs;
51 	}
52 
53 	return NULL;
54 }
55 
56 static bool
57 dev_allowed(const char *dev_name)
58 {
59 	struct rte_devargs *devargs;
60 
61 	devargs = dev_devargs(dev_name);
62 	if (devargs == NULL)
63 		return true;
64 
65 	switch (platform_bus.bus.conf.scan_mode) {
66 	case RTE_BUS_SCAN_UNDEFINED:
67 	case RTE_BUS_SCAN_ALLOWLIST:
68 		if (devargs->policy == RTE_DEV_ALLOWED)
69 			return true;
70 		break;
71 	case RTE_BUS_SCAN_BLOCKLIST:
72 		if (devargs->policy == RTE_DEV_BLOCKED)
73 			return false;
74 		break;
75 	}
76 
77 	return true;
78 }
79 
80 static int
81 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 	pdev = calloc(1, sizeof(*pdev));
88 	if (pdev == NULL)
89 		return -ENOMEM;
90 
91 	rte_strscpy(pdev->name, dev_name, sizeof(pdev->name));
92 	pdev->device.name = pdev->name;
93 	pdev->device.devargs = dev_devargs(dev_name);
94 	pdev->device.bus = &platform_bus.bus;
95 	snprintf(path, sizeof(path), PLATFORM_BUS_DEVICES_PATH "/%s/numa_node", dev_name);
96 	pdev->device.numa_node = eal_parse_sysfs_value(path, &val) ? rte_socket_id() : val;
97 
98 	FOREACH_DEVICE_ON_PLATFORM_BUS(tmp) {
99 		if (!strcmp(tmp->name, pdev->name)) {
100 			PLATFORM_LOG_LINE(INFO, "device %s already added", pdev->name);
101 
102 			if (tmp->device.devargs != pdev->device.devargs)
103 				rte_devargs_remove(pdev->device.devargs);
104 
105 			free(pdev);
106 			return -EEXIST;
107 		}
108 	}
109 
110 	TAILQ_INSERT_HEAD(&platform_bus.device_list, pdev, next);
111 
112 	PLATFORM_LOG_LINE(INFO, "adding device %s to the list", dev_name);
113 
114 	return 0;
115 }
116 
117 static char *
118 dev_kernel_driver_name(const char *dev_name)
119 {
120 	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 	ret = readlink(path, buf, sizeof(buf) - 1);
127 	if (ret <= 0)
128 		return NULL;
129 
130 	/* last token is kernel driver name */
131 	kdrv = strrchr(buf, '/');
132 	if (kdrv != NULL)
133 		return strdup(kdrv + 1);
134 
135 	return NULL;
136 }
137 
138 static bool
139 dev_is_bound_vfio_platform(const char *dev_name)
140 {
141 	char *kdrv;
142 	int ret;
143 
144 	kdrv = dev_kernel_driver_name(dev_name);
145 	if (!kdrv)
146 		return false;
147 
148 	ret = strcmp(kdrv, "vfio-platform");
149 	free(kdrv);
150 
151 	return ret == 0;
152 }
153 
154 static int
155 platform_bus_scan(void)
156 {
157 	const struct dirent *ent;
158 	const char *dev_name;
159 	int ret = 0;
160 	DIR *dp;
161 
162 	dp = opendir(PLATFORM_BUS_DEVICES_PATH);
163 	if (dp == NULL) {
164 		PLATFORM_LOG_LINE(INFO, "failed to open %s", PLATFORM_BUS_DEVICES_PATH);
165 		return -errno;
166 	}
167 
168 	while ((ent = readdir(dp))) {
169 		dev_name = ent->d_name;
170 		if (dev_name[0] == '.')
171 			continue;
172 
173 		if (!dev_allowed(dev_name))
174 			continue;
175 
176 		if (!dev_is_bound_vfio_platform(dev_name))
177 			continue;
178 
179 		ret = dev_add(dev_name);
180 		if (ret)
181 			break;
182 	}
183 
184 	closedir(dp);
185 
186 	return ret;
187 }
188 
189 static int
190 device_map_resource_offset(struct rte_platform_device *pdev, struct rte_platform_resource *res,
191 			   size_t offset)
192 {
193 	res->mem.addr = mmap(NULL, res->mem.len, PROT_READ | PROT_WRITE, MAP_SHARED, pdev->dev_fd,
194 			     offset);
195 	if (res->mem.addr == MAP_FAILED)
196 		return -errno;
197 
198 	PLATFORM_LOG_LINE(DEBUG, "adding resource va = %p len = %"PRIu64" name = %s", res->mem.addr,
199 		     res->mem.len, res->name);
200 
201 	return 0;
202 }
203 
204 static void
205 device_unmap_resources(struct rte_platform_device *pdev)
206 {
207 	struct rte_platform_resource *res;
208 	unsigned int i;
209 
210 	for (i = 0; i < pdev->num_resource; i++) {
211 		res = &pdev->resource[i];
212 		munmap(res->mem.addr, res->mem.len);
213 		free(res->name);
214 	}
215 
216 	free(pdev->resource);
217 	pdev->resource = NULL;
218 	pdev->num_resource = 0;
219 }
220 
221 static int
222 read_sysfs_string(const char *path, char *buf, size_t size)
223 {
224 	FILE *f;
225 	char *p;
226 
227 	f = fopen(path, "r");
228 	if (f == NULL)
229 		return -errno;
230 
231 	if (fgets(buf, size, f) == NULL) {
232 		fclose(f);
233 		return -ENODATA;
234 	}
235 
236 	fclose(f);
237 
238 	p = strrchr(buf, '\n');
239 	if (p != NULL)
240 		*p = '\0';
241 
242 	return 0;
243 }
244 
245 static char *
246 of_resource_name(const char *dev_name, int index)
247 {
248 	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 	ret = read_sysfs_string(path, buf, sizeof(buf) - 1);
254 	if (ret)
255 		return NULL;
256 
257 	for (name = buf; *name != 0; name += strlen(name) + 1) {
258 		if (num++ != index)
259 			continue;
260 		return strdup(name);
261 	}
262 
263 	return NULL;
264 }
265 
266 static int
267 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 	if (num == 0) {
274 		PLATFORM_LOG_LINE(WARNING, "device %s has no resources", pdev->name);
275 		return 0;
276 	}
277 
278 	pdev->resource = calloc(num, sizeof(*pdev->resource));
279 	if (pdev->resource == NULL)
280 		return -ENOMEM;
281 
282 	for (i = 0; i < num; i++) {
283 		struct vfio_region_info reg_info = {
284 			.argsz = sizeof(reg_info),
285 			.index = i,
286 		};
287 
288 		ret = ioctl(pdev->dev_fd, VFIO_DEVICE_GET_REGION_INFO, &reg_info);
289 		if (ret) {
290 			PLATFORM_LOG_LINE(ERR, "failed to get region info at %d", i);
291 			ret = -errno;
292 			goto out;
293 		}
294 
295 		res = &pdev->resource[i];
296 		res->name = of_resource_name(pdev->name, reg_info.index);
297 		res->mem.len = reg_info.size;
298 		ret = device_map_resource_offset(pdev, res, reg_info.offset);
299 		if (ret) {
300 			PLATFORM_LOG_LINE(ERR, "failed to ioremap resource at %d", i);
301 			goto out;
302 		}
303 
304 		pdev->num_resource++;
305 	}
306 
307 	return 0;
308 out:
309 	device_unmap_resources(pdev);
310 
311 	return ret;
312 }
313 
314 static void
315 device_cleanup(struct rte_platform_device *pdev)
316 {
317 	device_unmap_resources(pdev);
318 	rte_vfio_release_device(PLATFORM_BUS_DEVICES_PATH, pdev->name, pdev->dev_fd);
319 }
320 
321 static int
322 device_setup(struct rte_platform_device *pdev)
323 {
324 	struct vfio_device_info dev_info = { .argsz = sizeof(dev_info), };
325 	const char *name = pdev->name;
326 	int ret;
327 
328 	ret = rte_vfio_setup_device(PLATFORM_BUS_DEVICES_PATH, name, &pdev->dev_fd, &dev_info);
329 	if (ret) {
330 		PLATFORM_LOG_LINE(ERR, "failed to setup %s", name);
331 		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 	if (!(dev_info.flags & VFIO_DEVICE_FLAGS_PLATFORM)) {
345 		PLATFORM_LOG_LINE(ERR, "device not backed by vfio-platform");
346 		ret = -ENOTSUP;
347 		goto out;
348 	}
349 #endif
350 
351 	ret = device_map_resources(pdev, dev_info.num_regions);
352 	if (ret) {
353 		PLATFORM_LOG_LINE(ERR, "failed to setup platform resources");
354 		goto out;
355 	}
356 
357 	return 0;
358 out:
359 	device_cleanup(pdev);
360 
361 	return ret;
362 }
363 
364 static int
365 driver_call_probe(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev)
366 {
367 	int ret;
368 
369 	if (rte_dev_is_probed(&pdev->device))
370 		return -EBUSY;
371 
372 	if (pdrv->probe != NULL) {
373 		pdev->driver = pdrv;
374 		ret = pdrv->probe(pdev);
375 		if (ret)
376 			return ret;
377 	}
378 
379 	pdev->device.driver = &pdrv->driver;
380 
381 	return 0;
382 }
383 
384 static int
385 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 	iova_mode = rte_eal_iova_mode();
391 	if (pdrv->drv_flags & RTE_PLATFORM_DRV_NEED_IOVA_AS_VA && iova_mode != RTE_IOVA_VA) {
392 		PLATFORM_LOG_LINE(ERR, "driver %s expects VA IOVA mode but current mode is PA",
393 			     pdrv->driver.name);
394 		return -EINVAL;
395 	}
396 
397 	ret = device_setup(pdev);
398 	if (ret)
399 		return ret;
400 
401 	ret = driver_call_probe(pdrv, pdev);
402 	if (ret)
403 		device_cleanup(pdev);
404 
405 	return ret;
406 }
407 
408 static bool
409 driver_match_device(struct rte_platform_driver *pdrv, struct rte_platform_device *pdev)
410 {
411 	bool match = false;
412 	char *kdrv;
413 
414 	kdrv = dev_kernel_driver_name(pdev->name);
415 	if (!kdrv)
416 		return false;
417 
418 	/* match by driver name */
419 	if (!strcmp(kdrv, pdrv->driver.name)) {
420 		match = true;
421 		goto out;
422 	}
423 
424 	/* match by driver alias */
425 	if (pdrv->driver.alias != NULL && !strcmp(kdrv, pdrv->driver.alias)) {
426 		match = true;
427 		goto out;
428 	}
429 
430 	/* match by device name */
431 	if (!strcmp(pdev->name, pdrv->driver.name))
432 		match = true;
433 
434 out:
435 	free(kdrv);
436 
437 	return match;
438 }
439 
440 static int
441 device_attach(struct rte_platform_device *pdev)
442 {
443 	struct rte_platform_driver *pdrv;
444 
445 	FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) {
446 		if (driver_match_device(pdrv, pdev))
447 			break;
448 	}
449 
450 	if (pdrv == NULL)
451 		return -ENODEV;
452 
453 	return driver_probe_device(pdrv, pdev);
454 }
455 
456 static int
457 platform_bus_probe(void)
458 {
459 	struct rte_platform_device *pdev;
460 	int ret;
461 
462 	FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) {
463 		ret = device_attach(pdev);
464 		if (ret == -EBUSY) {
465 			PLATFORM_LOG_LINE(DEBUG, "device %s already probed", pdev->name);
466 			continue;
467 		}
468 		if (ret)
469 			PLATFORM_LOG_LINE(ERR, "failed to probe %s", pdev->name);
470 	}
471 
472 	return 0;
473 }
474 
475 static struct rte_device *
476 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 	pdev = start ? RTE_TAILQ_NEXT(RTE_DEV_TO_PLATFORM_DEV_CONST(start), next) :
481 		       RTE_TAILQ_FIRST(&platform_bus.device_list);
482 	while (pdev) {
483 		if (cmp(&pdev->device, data) == 0)
484 			return &pdev->device;
485 
486 		pdev = RTE_TAILQ_NEXT(pdev, next);
487 	}
488 
489 	return NULL;
490 }
491 
492 static int
493 platform_bus_plug(struct rte_device *dev)
494 {
495 	struct rte_platform_device *pdev;
496 
497 	if (!dev_allowed(dev->name))
498 		return -EPERM;
499 
500 	if (!dev_is_bound_vfio_platform(dev->name))
501 		return -EPERM;
502 
503 	pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
504 	if (pdev == NULL)
505 		return -EINVAL;
506 
507 	return device_attach(pdev);
508 }
509 
510 static void
511 device_release_driver(struct rte_platform_device *pdev)
512 {
513 	struct rte_platform_driver *pdrv;
514 	int ret;
515 
516 	pdrv = pdev->driver;
517 	if (pdrv != NULL && pdrv->remove != NULL) {
518 		ret = pdrv->remove(pdev);
519 		if (ret)
520 			PLATFORM_LOG_LINE(WARNING, "failed to remove %s", pdev->name);
521 	}
522 
523 	pdev->device.driver = NULL;
524 	pdev->driver = NULL;
525 }
526 
527 static int
528 platform_bus_unplug(struct rte_device *dev)
529 {
530 	struct rte_platform_device *pdev;
531 
532 	pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
533 	if (pdev == NULL)
534 		return -EINVAL;
535 
536 	device_release_driver(pdev);
537 	device_cleanup(pdev);
538 	rte_devargs_remove(pdev->device.devargs);
539 	free(pdev);
540 
541 	return 0;
542 }
543 
544 static int
545 platform_bus_parse(const char *name, void *addr)
546 {
547 	struct rte_platform_device pdev = { };
548 	struct rte_platform_driver *pdrv;
549 	const char **out = addr;
550 
551 	rte_strscpy(pdev.name, name, sizeof(pdev.name));
552 
553 	FOREACH_DRIVER_ON_PLATFORM_BUS(pdrv) {
554 		if (driver_match_device(pdrv, &pdev))
555 			break;
556 	}
557 
558 	if (pdrv != NULL && addr != NULL)
559 		*out = name;
560 
561 	return pdrv != NULL ? 0 : -ENODEV;
562 }
563 
564 static int
565 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 	pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
570 	if (pdev == NULL || pdev->driver == NULL) {
571 		rte_errno = EINVAL;
572 		return -1;
573 	}
574 
575 	if (pdev->driver->dma_map != NULL)
576 		return pdev->driver->dma_map(pdev, addr, iova, len);
577 
578 	return rte_vfio_container_dma_map(RTE_VFIO_DEFAULT_CONTAINER_FD, (uint64_t)addr, iova, len);
579 }
580 
581 static int
582 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 	pdev = RTE_DEV_TO_PLATFORM_DEV(dev);
587 	if (pdev == NULL || pdev->driver == NULL) {
588 		rte_errno = EINVAL;
589 		return -1;
590 	}
591 
592 	if (pdev->driver->dma_unmap != NULL)
593 		return pdev->driver->dma_unmap(pdev, addr, iova, len);
594 
595 	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 platform_bus_get_iommu_class(void)
601 {
602 	struct rte_platform_driver *pdrv;
603 	struct rte_platform_device *pdev;
604 
605 	FOREACH_DEVICE_ON_PLATFORM_BUS(pdev) {
606 		pdrv = pdev->driver;
607 		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 platform_bus_cleanup(void)
616 {
617 	struct rte_platform_device *pdev, *tmp;
618 
619 	RTE_TAILQ_FOREACH_SAFE(pdev, &platform_bus.device_list, next, tmp) {
620 		TAILQ_REMOVE(&platform_bus.device_list, pdev, next);
621 		platform_bus_unplug(&pdev->device);
622 	}
623 
624 	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 RTE_REGISTER_BUS(platform, platform_bus.bus);
646 RTE_LOG_REGISTER_DEFAULT(platform_bus_logtype, NOTICE);
647 
648 #endif /* VFIO_PRESENT */
649