1 /*
2  * Copyright (c) 2015, Xilinx Inc. and Contributors. All rights reserved.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 /*
8  * @file	linux/device.c
9  * @brief	Linux libmetal device operations.
10  */
11 
12 #include <metal/device.h>
13 #include <metal/sys.h>
14 #include <metal/utilities.h>
15 #include <metal/irq.h>
16 
17 #define MAX_DRIVERS	64
18 
19 struct linux_bus;
20 struct linux_device;
21 
22 struct linux_driver {
23 	const char		*drv_name;
24 	const char		*mod_name;
25 	const char		*cls_name;
26 	struct sysfs_driver	*sdrv;
27 	int			(*dev_open)(struct linux_bus *lbus,
28 					    struct linux_device *ldev);
29 	void			(*dev_close)(struct linux_bus *lbus,
30 					     struct linux_device *ldev);
31 	void			(*dev_irq_ack)(struct linux_bus *lbus,
32 					     struct linux_device *ldev,
33 					     int irq);
34 	int			(*dev_dma_map)(struct linux_bus *lbus,
35 						struct linux_device *ldev,
36 						uint32_t dir,
37 						struct metal_sg *sg_in,
38 						int nents_in,
39 						struct metal_sg *sg_out);
40 	void			(*dev_dma_unmap)(struct linux_bus *lbus,
41 						struct linux_device *ldev,
42 						uint32_t dir,
43 						struct metal_sg *sg,
44 						int nents);
45 };
46 
47 struct linux_bus {
48 	struct metal_bus	bus;
49 	const char		*bus_name;
50 	struct linux_driver	drivers[MAX_DRIVERS];
51 	struct sysfs_bus	*sbus;
52 };
53 
54 struct linux_device {
55 	struct metal_device		device;
56 	char				dev_name[PATH_MAX];
57 	char				dev_path[PATH_MAX];
58 	char				cls_path[PATH_MAX];
59 	metal_phys_addr_t		region_phys[METAL_MAX_DEVICE_REGIONS];
60 	struct linux_driver		*ldrv;
61 	struct sysfs_device		*sdev;
62 	struct sysfs_attribute		*override;
63 	int				fd;
64 };
65 
to_linux_bus(struct metal_bus * bus)66 static struct linux_bus *to_linux_bus(struct metal_bus *bus)
67 {
68 	return metal_container_of(bus, struct linux_bus, bus);
69 }
70 
to_linux_device(struct metal_device * device)71 static struct linux_device *to_linux_device(struct metal_device *device)
72 {
73 	return metal_container_of(device, struct linux_device, device);
74 }
75 
metal_uio_read_map_attr(struct linux_device * ldev,unsigned int index,const char * name,unsigned long * value)76 static int metal_uio_read_map_attr(struct linux_device *ldev,
77 				   unsigned int index,
78 				   const char *name,
79 				   unsigned long *value)
80 {
81 	const char *cls = ldev->cls_path;
82 	struct sysfs_attribute *attr;
83 	char path[SYSFS_PATH_MAX];
84 	int result;
85 
86 	result = snprintf(path, sizeof(path), "%s/maps/map%u/%s", cls, index, name);
87 	if (result >= (int)sizeof(path))
88 		return -EOVERFLOW;
89 	attr = sysfs_open_attribute(path);
90 	if (!attr || sysfs_read_attribute(attr) != 0) {
91 		sysfs_close_attribute(attr);
92 		return -errno;
93 	}
94 
95 	*value = strtoul(attr->value, NULL, 0);
96 
97 	sysfs_close_attribute(attr);
98 	return 0;
99 }
100 
metal_uio_dev_bind(struct linux_device * ldev,struct linux_driver * ldrv)101 static int metal_uio_dev_bind(struct linux_device *ldev,
102 			      struct linux_driver *ldrv)
103 {
104 	struct sysfs_attribute *attr;
105 	int result;
106 
107 	if (strcmp(ldev->sdev->driver_name, ldrv->drv_name) == 0)
108 		return 0;
109 
110 	if (strcmp(ldev->sdev->driver_name, SYSFS_UNKNOWN) != 0) {
111 		metal_log(METAL_LOG_INFO, "device %s in use by driver %s\n",
112 			  ldev->dev_name, ldev->sdev->driver_name);
113 		return -EBUSY;
114 	}
115 
116 	attr = sysfs_get_device_attr(ldev->sdev, "driver_override");
117 	if (!attr) {
118 		metal_log(METAL_LOG_ERROR, "device %s has no override\n",
119 			  ldev->dev_name);
120 		return -errno;
121 	}
122 
123 	result = sysfs_write_attribute(attr, ldrv->drv_name,
124 				       strlen(ldrv->drv_name));
125 	if (result) {
126 		metal_log(METAL_LOG_ERROR, "failed to set override on %s\n",
127 			  ldev->dev_name);
128 		return -errno;
129 	}
130 	ldev->override = attr;
131 
132 	attr = sysfs_get_driver_attr(ldrv->sdrv, "bind");
133 	if (!attr) {
134 		metal_log(METAL_LOG_ERROR, "driver %s has no bind\n", ldrv->drv_name);
135 		return -ENOTSUP;
136 	}
137 
138 	result = sysfs_write_attribute(attr, ldev->dev_name,
139 				       strlen(ldev->dev_name));
140 	if (result) {
141 		metal_log(METAL_LOG_ERROR, "failed to bind %s to %s\n",
142 			  ldev->dev_name, ldrv->drv_name);
143 		return -errno;
144 	}
145 
146 	metal_log(METAL_LOG_DEBUG, "bound device %s to driver %s\n",
147 		  ldev->dev_name, ldrv->drv_name);
148 
149 	return 0;
150 }
151 
metal_uio_dev_open(struct linux_bus * lbus,struct linux_device * ldev)152 static int metal_uio_dev_open(struct linux_bus *lbus, struct linux_device *ldev)
153 {
154 	char *instance, path[SYSFS_PATH_MAX];
155 	struct linux_driver *ldrv = ldev->ldrv;
156 	unsigned long *phys, offset = 0, size = 0;
157 	struct metal_io_region *io;
158 	struct dlist *dlist;
159 	int result, i;
160 	void *virt;
161 	int irq_info;
162 
163 
164 	ldev->fd = -1;
165 	ldev->device.irq_info = (void *)-1;
166 
167 	ldev->sdev = sysfs_open_device(lbus->bus_name, ldev->dev_name);
168 	if (!ldev->sdev) {
169 		metal_log(METAL_LOG_ERROR, "device %s:%s not found\n",
170 			  lbus->bus_name, ldev->dev_name);
171 		return -ENODEV;
172 	}
173 	metal_log(METAL_LOG_DEBUG, "opened sysfs device %s:%s\n",
174 		  lbus->bus_name, ldev->dev_name);
175 
176 	result = metal_uio_dev_bind(ldev, ldrv);
177 	if (result)
178 		return result;
179 
180 	result = snprintf(path, sizeof(path), "%s/uio", ldev->sdev->path);
181 	if (result >= (int)sizeof(path))
182 		return -EOVERFLOW;
183 	dlist = sysfs_open_directory_list(path);
184 	if (!dlist) {
185 		metal_log(METAL_LOG_ERROR, "failed to scan class path %s\n",
186 			  path);
187 		return -errno;
188 	}
189 
190 	dlist_for_each_data(dlist, instance, char) {
191 		result = snprintf(ldev->cls_path, sizeof(ldev->cls_path),
192 				  "%s/%s", path, instance);
193 		if (result >= (int)sizeof(ldev->cls_path))
194 			return -EOVERFLOW;
195 		result = snprintf(ldev->dev_path, sizeof(ldev->dev_path),
196 				  "/dev/%s", instance);
197 		if (result >= (int)sizeof(ldev->dev_path))
198 			return -EOVERFLOW;
199 		break;
200 	}
201 	sysfs_close_list(dlist);
202 
203 	if (sysfs_path_is_dir(ldev->cls_path) != 0) {
204 		metal_log(METAL_LOG_ERROR, "invalid device class path %s\n",
205 			  ldev->cls_path);
206 		return -ENODEV;
207 	}
208 
209 	i = 0;
210 	do {
211 		if (!access(ldev->dev_path, F_OK))
212 			break;
213 		usleep(10);
214 		i++;
215 	} while (i < 1000);
216 	if (i >= 1000) {
217 		metal_log(METAL_LOG_ERROR, "failed to open file %s, timeout.\n",
218 			  ldev->dev_path);
219 		return -ENODEV;
220 	}
221 	result = metal_open(ldev->dev_path, 0);
222 	if (result < 0) {
223 		metal_log(METAL_LOG_ERROR, "failed to open device %s\n",
224 			  ldev->dev_path, strerror(-result));
225 		return result;
226 	}
227 	ldev->fd = result;
228 
229 	metal_log(METAL_LOG_DEBUG, "opened %s:%s as %s\n",
230 		  lbus->bus_name, ldev->dev_name, ldev->dev_path);
231 
232 	for (i = 0, result = 0; !result && i < METAL_MAX_DEVICE_REGIONS; i++) {
233 		phys = &ldev->region_phys[ldev->device.num_regions];
234 		result = (result ? result :
235 			 metal_uio_read_map_attr(ldev, i, "offset", &offset));
236 		result = (result ? result :
237 			 metal_uio_read_map_attr(ldev, i, "addr", phys));
238 		result = (result ? result :
239 			 metal_uio_read_map_attr(ldev, i, "size", &size));
240 		result = (result ? result :
241 			 metal_map(ldev->fd, i * getpagesize(), size, 0, 0, &virt));
242 		if (!result) {
243 			io = &ldev->device.regions[ldev->device.num_regions];
244 			metal_io_init(io, virt, phys, size, -1, 0, NULL);
245 			ldev->device.num_regions++;
246 		}
247 	}
248 
249 	irq_info = 1;
250 	if (write(ldev->fd, &irq_info, sizeof(irq_info)) <= 0) {
251 		metal_log(METAL_LOG_INFO,
252 			  "%s: No IRQ for device %s.\n",
253 			  __func__, ldev->dev_name);
254 		ldev->device.irq_num =  0;
255 		ldev->device.irq_info = (void *)-1;
256 	} else {
257 		ldev->device.irq_num =  1;
258 		ldev->device.irq_info = (void *)(intptr_t)ldev->fd;
259 		metal_linux_irq_register_dev(&ldev->device, ldev->fd);
260 	}
261 
262 	return 0;
263 }
264 
metal_uio_dev_close(struct linux_bus * lbus,struct linux_device * ldev)265 static void metal_uio_dev_close(struct linux_bus *lbus,
266 				struct linux_device *ldev)
267 {
268 	(void)lbus;
269 	unsigned int i;
270 
271 	for (i = 0; i < ldev->device.num_regions; i++) {
272 		metal_unmap(ldev->device.regions[i].virt,
273 			    ldev->device.regions[i].size);
274 	}
275 	if (ldev->override) {
276 		sysfs_write_attribute(ldev->override, "", 1);
277 		ldev->override = NULL;
278 	}
279 	if (ldev->sdev) {
280 		sysfs_close_device(ldev->sdev);
281 		ldev->sdev = NULL;
282 	}
283 	if (ldev->fd >= 0) {
284 		close(ldev->fd);
285 	}
286 }
287 
metal_uio_dev_irq_ack(struct linux_bus * lbus,struct linux_device * ldev,int irq)288 static void metal_uio_dev_irq_ack(struct linux_bus *lbus,
289 				 struct linux_device *ldev,
290 				 int irq)
291 {
292 	(void)lbus;
293 	(void)irq;
294 	int irq_info = 1;
295 	unsigned int val;
296 	int ret;
297 
298 	ret = read(ldev->fd, (void *)&val, sizeof(val));
299 	if (ret < 0) {
300 		metal_log(METAL_LOG_ERROR, "%s, read uio irq fd %d failed: %d.\n",
301 						__func__, ldev->fd, ret);
302 		return;
303 	}
304 	ret = write(ldev->fd, &irq_info, sizeof(irq_info));
305 	if (ret < 0) {
306 		metal_log(METAL_LOG_ERROR, "%s, write uio irq fd %d failed: %d.\n",
307 						__func__, ldev->fd, errno);
308 	}
309 }
310 
metal_uio_dev_dma_map(struct linux_bus * lbus,struct linux_device * ldev,uint32_t dir,struct metal_sg * sg_in,int nents_in,struct metal_sg * sg_out)311 static int metal_uio_dev_dma_map(struct linux_bus *lbus,
312 				 struct linux_device *ldev,
313 				 uint32_t dir,
314 				 struct metal_sg *sg_in,
315 				 int nents_in,
316 				 struct metal_sg *sg_out)
317 {
318 	int i, j;
319 	void *vaddr_sg_lo, *vaddr_sg_hi, *vaddr_lo, *vaddr_hi;
320 	struct metal_io_region *io;
321 
322 	(void)lbus;
323 	(void)dir;
324 
325 	/* Check if the the input virt address is MMIO address */
326 	for (i = 0; i < nents_in; i++) {
327 		vaddr_sg_lo = sg_in[i].virt;
328 		vaddr_sg_hi = vaddr_sg_lo + sg_in[i].len;
329 		for (j = 0, io = ldev->device.regions;
330 		     j < (int)ldev->device.num_regions; j++, io++) {
331 			vaddr_lo = io->virt;
332 			vaddr_hi = vaddr_lo + io->size;
333 			if (vaddr_sg_lo >= vaddr_lo &&
334 			    vaddr_sg_hi <= vaddr_hi) {
335 				break;
336 			}
337 		}
338 		if (j == (int)ldev->device.num_regions) {
339 			metal_log(METAL_LOG_WARNING,
340 			  "%s,%s: input address isn't MMIO addr: 0x%x,%d.\n",
341 			__func__, ldev->dev_name, vaddr_sg_lo, sg_in[i].len);
342 			return -EINVAL;
343 		}
344 	}
345 	if (sg_out != sg_in)
346 		memcpy(sg_out, sg_in, nents_in*(sizeof(struct metal_sg)));
347 	return nents_in;
348 }
349 
metal_uio_dev_dma_unmap(struct linux_bus * lbus,struct linux_device * ldev,uint32_t dir,struct metal_sg * sg,int nents)350 static void metal_uio_dev_dma_unmap(struct linux_bus *lbus,
351 				    struct linux_device *ldev,
352 				    uint32_t dir,
353 				    struct metal_sg *sg,
354 				    int nents)
355 {
356 	(void) lbus;
357 	(void) ldev;
358 	(void) dir;
359 	(void) sg;
360 	(void) nents;
361 }
362 
363 static struct linux_bus linux_bus[] = {
364 	{
365 		.bus_name	= "platform",
366 		.drivers = {
367 			{
368 				.drv_name  = "uio_pdrv_genirq",
369 				.mod_name  = "uio_pdrv_genirq",
370 				.cls_name  = "uio",
371 				.dev_open  = metal_uio_dev_open,
372 				.dev_close = metal_uio_dev_close,
373 				.dev_irq_ack  = metal_uio_dev_irq_ack,
374 				.dev_dma_map = metal_uio_dev_dma_map,
375 				.dev_dma_unmap = metal_uio_dev_dma_unmap,
376 			},
377 			{
378 				.drv_name  = "uio_dmem_genirq",
379 				.mod_name  = "uio_dmem_genirq",
380 				.cls_name  = "uio",
381 				.dev_open  = metal_uio_dev_open,
382 				.dev_close = metal_uio_dev_close,
383 				.dev_irq_ack  = metal_uio_dev_irq_ack,
384 				.dev_dma_map = metal_uio_dev_dma_map,
385 				.dev_dma_unmap = metal_uio_dev_dma_unmap,
386 			},
387 			{ 0 /* sentinel */ }
388 		}
389 	},
390 	{
391 		.bus_name	= "pci",
392 		.drivers = {
393 			{
394 				.drv_name  = "vfio-pci",
395 				.mod_name  = "vfio-pci",
396 			},
397 			{
398 				.drv_name  = "uio_pci_generic",
399 				.mod_name  = "uio_pci_generic",
400 				.cls_name  = "uio",
401 				.dev_open  = metal_uio_dev_open,
402 				.dev_close = metal_uio_dev_close,
403 				.dev_irq_ack  = metal_uio_dev_irq_ack,
404 				.dev_dma_map = metal_uio_dev_dma_map,
405 				.dev_dma_unmap = metal_uio_dev_dma_unmap,
406 			},
407 			{ 0 /* sentinel */ }
408 		}
409 	},
410 	{
411 		/* sentinel */
412 		.bus_name = NULL,
413 	},
414 };
415 
416 #define for_each_linux_bus(lbus)					\
417 	for ((lbus) = linux_bus; (lbus)->bus_name; (lbus)++)
418 #define for_each_linux_driver(lbus, ldrv)			\
419 	for ((ldrv) = lbus->drivers; (ldrv)->drv_name; (ldrv)++)
420 
421 
metal_linux_dev_open(struct metal_bus * bus,const char * dev_name,struct metal_device ** device)422 static int metal_linux_dev_open(struct metal_bus *bus,
423 				const char *dev_name,
424 				struct metal_device **device)
425 {
426 	struct linux_bus *lbus = to_linux_bus(bus);
427 	struct linux_device *ldev = NULL;
428 	struct linux_driver *ldrv;
429 	int error;
430 
431 	ldev = malloc(sizeof(*ldev));
432 	if (!ldev)
433 		return -ENOMEM;
434 
435 	for_each_linux_driver(lbus, ldrv) {
436 
437 		/* Check if we have a viable driver. */
438 		if (!ldrv->sdrv || !ldrv->dev_open)
439 			continue;
440 
441 		/* Allocate a linux device if we haven't already. */
442 		if (!ldev)
443 			ldev = malloc(sizeof(*ldev));
444 		if (!ldev)
445 			return -ENOMEM;
446 
447 		/* Reset device data. */
448 		memset(ldev, 0, sizeof(*ldev));
449 		strncpy(ldev->dev_name, dev_name, sizeof(ldev->dev_name) - 1);
450 		ldev->fd = -1;
451 		ldev->ldrv = ldrv;
452 		ldev->device.bus = bus;
453 
454 		/* Try and open the device. */
455 		error = ldrv->dev_open(lbus, ldev);
456 		if (error) {
457 			ldrv->dev_close(lbus, ldev);
458 			continue;
459 		}
460 
461 		*device = &ldev->device;
462 		(*device)->name = ldev->dev_name;
463 
464 		metal_list_add_tail(&bus->devices, &(*device)->node);
465 		return 0;
466 	}
467 
468 	if (ldev)
469 		free(ldev);
470 
471 	return -ENODEV;
472 }
473 
metal_linux_dev_close(struct metal_bus * bus,struct metal_device * device)474 static void metal_linux_dev_close(struct metal_bus *bus,
475 				  struct metal_device *device)
476 {
477 	struct linux_device *ldev = to_linux_device(device);
478 	struct linux_bus *lbus = to_linux_bus(bus);
479 
480 	ldev->ldrv->dev_close(lbus, ldev);
481 	metal_list_del(&device->node);
482 	free(ldev);
483 }
484 
metal_linux_bus_close(struct metal_bus * bus)485 static void metal_linux_bus_close(struct metal_bus *bus)
486 {
487 	struct linux_bus *lbus = to_linux_bus(bus);
488 	struct linux_driver *ldrv;
489 
490 	for_each_linux_driver(lbus, ldrv) {
491 		if (ldrv->sdrv)
492 			sysfs_close_driver(ldrv->sdrv);
493 		ldrv->sdrv = NULL;
494 	}
495 
496 	sysfs_close_bus(lbus->sbus);
497 	lbus->sbus = NULL;
498 }
499 
metal_linux_dev_irq_ack(struct metal_bus * bus,struct metal_device * device,int irq)500 static void metal_linux_dev_irq_ack(struct metal_bus *bus,
501 			     struct metal_device *device,
502 			     int irq)
503 {
504 	struct linux_device *ldev = to_linux_device(device);
505 	struct linux_bus *lbus = to_linux_bus(bus);
506 
507 	return ldev->ldrv->dev_irq_ack(lbus, ldev, irq);
508 }
509 
metal_linux_dev_dma_map(struct metal_bus * bus,struct metal_device * device,uint32_t dir,struct metal_sg * sg_in,int nents_in,struct metal_sg * sg_out)510 static int metal_linux_dev_dma_map(struct metal_bus *bus,
511 			     struct metal_device *device,
512 			     uint32_t dir,
513 			     struct metal_sg *sg_in,
514 			     int nents_in,
515 			     struct metal_sg *sg_out)
516 {
517 	struct linux_device *ldev = to_linux_device(device);
518 	struct linux_bus *lbus = to_linux_bus(bus);
519 
520 	return ldev->ldrv->dev_dma_map(lbus, ldev, dir, sg_in,
521 				       nents_in, sg_out);
522 }
523 
metal_linux_dev_dma_unmap(struct metal_bus * bus,struct metal_device * device,uint32_t dir,struct metal_sg * sg,int nents)524 static void metal_linux_dev_dma_unmap(struct metal_bus *bus,
525 				      struct metal_device *device,
526 				      uint32_t dir,
527 				      struct metal_sg *sg,
528 				      int nents)
529 {
530 	struct linux_device *ldev = to_linux_device(device);
531 	struct linux_bus *lbus = to_linux_bus(bus);
532 
533 	ldev->ldrv->dev_dma_unmap(lbus, ldev, dir, sg,
534 				       nents);
535 }
536 
537 static const struct metal_bus_ops metal_linux_bus_ops = {
538 	.bus_close	= metal_linux_bus_close,
539 	.dev_open	= metal_linux_dev_open,
540 	.dev_close	= metal_linux_dev_close,
541 	.dev_irq_ack	= metal_linux_dev_irq_ack,
542 	.dev_dma_map	= metal_linux_dev_dma_map,
543 	.dev_dma_unmap	= metal_linux_dev_dma_unmap,
544 };
545 
metal_linux_register_bus(struct linux_bus * lbus)546 static int metal_linux_register_bus(struct linux_bus *lbus)
547 {
548 	lbus->bus.name = lbus->bus_name;
549 	lbus->bus.ops  = metal_linux_bus_ops;
550 	return metal_bus_register(&lbus->bus);
551 }
552 
metal_linux_probe_driver(struct linux_bus * lbus,struct linux_driver * ldrv)553 static int metal_linux_probe_driver(struct linux_bus *lbus,
554 				    struct linux_driver *ldrv)
555 {
556 	char command[256];
557 	int ret;
558 
559 	ldrv->sdrv = sysfs_open_driver(lbus->bus_name, ldrv->drv_name);
560 
561 	/* Try probing the module and then open the driver. */
562 	if (!ldrv->sdrv) {
563 		ret = snprintf(command, sizeof(command),
564 			       "modprobe %s > /dev/null 2>&1", ldrv->mod_name);
565 		if (ret >= (int)sizeof(command))
566 			return -EOVERFLOW;
567 		ret = system(command);
568 		if (ret < 0) {
569 			metal_log(METAL_LOG_WARNING,
570 				  "%s: executing system command '%s' failed.\n",
571 				  __func__, command);
572 		}
573 		ldrv->sdrv = sysfs_open_driver(lbus->bus_name, ldrv->drv_name);
574 	}
575 
576 	/* Try sudo probing the module and then open the driver. */
577 	if (!ldrv->sdrv) {
578 		ret = snprintf(command, sizeof(command),
579 			       "sudo modprobe %s > /dev/null 2>&1", ldrv->mod_name);
580 		if (ret >= (int)sizeof(command))
581 			return -EOVERFLOW;
582 		ret = system(command);
583 		if (ret < 0) {
584 			metal_log(METAL_LOG_WARNING,
585 				  "%s: executing system command '%s' failed.\n",
586 				  __func__, command);
587 		}
588 		ldrv->sdrv = sysfs_open_driver(lbus->bus_name, ldrv->drv_name);
589 	}
590 
591 	/* If all else fails... */
592 	return ldrv->sdrv ? 0 : -ENODEV;
593 }
594 
metal_linux_probe_bus(struct linux_bus * lbus)595 static int metal_linux_probe_bus(struct linux_bus *lbus)
596 {
597 	struct linux_driver *ldrv;
598 	int ret, error = -ENODEV;
599 
600 	lbus->sbus = sysfs_open_bus(lbus->bus_name);
601 	if (!lbus->sbus)
602 		return -ENODEV;
603 
604 	for_each_linux_driver(lbus, ldrv) {
605 		ret = metal_linux_probe_driver(lbus, ldrv);
606 		/* Clear the error if any driver is available */
607 		if (!ret)
608 			error = ret;
609 	}
610 
611 	if (error) {
612 		metal_linux_bus_close(&lbus->bus);
613 		return error;
614 	}
615 
616 	error = metal_linux_register_bus(lbus);
617 	if (error)
618 		metal_linux_bus_close(&lbus->bus);
619 
620 	return error;
621 }
622 
metal_linux_bus_init(void)623 int metal_linux_bus_init(void)
624 {
625 	struct linux_bus *lbus;
626 	int valid = 0;
627 
628 	for_each_linux_bus(lbus)
629 		valid += metal_linux_probe_bus(lbus) ? 0 : 1;
630 
631 	return valid ? 0 : -ENODEV;
632 }
633 
metal_linux_bus_finish(void)634 void metal_linux_bus_finish(void)
635 {
636 	struct linux_bus *lbus;
637 	struct metal_bus *bus;
638 
639 	for_each_linux_bus(lbus) {
640 		if (metal_bus_find(lbus->bus_name, &bus) == 0)
641 			metal_bus_unregister(bus);
642 	}
643 }
644 
metal_generic_dev_sys_open(struct metal_device * dev)645 int metal_generic_dev_sys_open(struct metal_device *dev)
646 {
647 	(void)dev;
648 	return 0;
649 }
650 
metal_linux_get_device_property(struct metal_device * device,const char * property_name,void * output,int len)651 int metal_linux_get_device_property(struct metal_device *device,
652 				    const char *property_name,
653 				    void *output, int len)
654 {
655 	int fd = 0;
656 	int status = 0;
657 	const int flags = O_RDONLY;
658 	const int mode = S_IRUSR | S_IRGRP | S_IROTH;
659 	struct linux_device *ldev = to_linux_device(device);
660 	char path[PATH_MAX];
661 
662 	snprintf(path, sizeof(path), "%s/of_node/%s",
663 			 ldev->sdev->path, property_name);
664 	fd = open(path, flags, mode);
665 	if (fd < 0)
666 		return -errno;
667 	if (read(fd, output, len) < 0) {
668 		status = -errno;
669 		close(fd);
670 		return status;
671 	}
672 
673 	status = close(fd);
674 	return status < 0 ? -errno : 0;
675 }
676 
677