1 /*
2 * The PCI Library -- Configuration Access via /sys/bus/pci
3 *
4 * Copyright (c) 2003 Matthew Wilcox <[email protected]>
5 * Copyright (c) 1997--2024 Martin Mares <[email protected]>
6 *
7 * Can be freely distributed and used under the terms of the GNU GPL v2+.
8 *
9 * SPDX-License-Identifier: GPL-2.0-or-later
10 */
11
12 #define _GNU_SOURCE
13
14 #include <stdio.h>
15 #include <stdlib.h>
16 #include <string.h>
17 #include <stdarg.h>
18 #include <unistd.h>
19 #include <errno.h>
20 #include <dirent.h>
21 #include <fcntl.h>
22 #include <libgen.h>
23 #include <sys/types.h>
24
25 #include "internal.h"
26
27 static void
sysfs_config(struct pci_access * a)28 sysfs_config(struct pci_access *a)
29 {
30 pci_define_param(a, "sysfs.path", PCI_PATH_SYS_BUS_PCI, "Path to the sysfs device tree");
31 }
32
33 static inline char *
sysfs_name(struct pci_access * a)34 sysfs_name(struct pci_access *a)
35 {
36 return pci_get_param(a, "sysfs.path");
37 }
38
39 static int
sysfs_detect(struct pci_access * a)40 sysfs_detect(struct pci_access *a)
41 {
42 if (access(sysfs_name(a), R_OK))
43 {
44 a->debug("...cannot open %s", sysfs_name(a));
45 return 0;
46 }
47 a->debug("...using %s", sysfs_name(a));
48 return 1;
49 }
50
51 static void
sysfs_init(struct pci_access * a)52 sysfs_init(struct pci_access *a)
53 {
54 a->fd = -1;
55 a->fd_vpd = -1;
56 }
57
58 static void
sysfs_flush_cache(struct pci_access * a)59 sysfs_flush_cache(struct pci_access *a)
60 {
61 if (a->fd >= 0)
62 {
63 close(a->fd);
64 a->fd = -1;
65 }
66 if (a->fd_vpd >= 0)
67 {
68 close(a->fd_vpd);
69 a->fd_vpd = -1;
70 }
71 a->cached_dev = NULL;
72 }
73
74 static void
sysfs_cleanup(struct pci_access * a)75 sysfs_cleanup(struct pci_access *a)
76 {
77 sysfs_flush_cache(a);
78 }
79
80 #define OBJNAMELEN 1024
81 static void
sysfs_obj_name(struct pci_dev * d,char * object,char * buf)82 sysfs_obj_name(struct pci_dev *d, char *object, char *buf)
83 {
84 int n = snprintf(buf, OBJNAMELEN, "%s/devices/%04x:%02x:%02x.%d/%s",
85 sysfs_name(d->access), d->domain, d->bus, d->dev, d->func, object);
86 if (n < 0 || n >= OBJNAMELEN)
87 d->access->error("File name too long");
88 }
89
90 #define OBJBUFSIZE 1024
91
92 static int
sysfs_get_string(struct pci_dev * d,char * object,char * buf,int mandatory)93 sysfs_get_string(struct pci_dev *d, char *object, char *buf, int mandatory)
94 {
95 struct pci_access *a = d->access;
96 int fd, n;
97 char namebuf[OBJNAMELEN];
98 void (*warn)(char *msg, ...) = (mandatory ? a->error : a->warning);
99
100 sysfs_obj_name(d, object, namebuf);
101 fd = open(namebuf, O_RDONLY);
102 if (fd < 0)
103 {
104 if (mandatory || errno != ENOENT)
105 warn("Cannot open %s: %s", namebuf, strerror(errno));
106 return 0;
107 }
108 n = read(fd, buf, OBJBUFSIZE);
109 int read_errno = errno;
110 close(fd);
111 if (n < 0)
112 {
113 warn("Error reading %s: %s", namebuf, strerror(read_errno));
114 return 0;
115 }
116 if (n >= OBJBUFSIZE)
117 {
118 warn("Value in %s too long", namebuf);
119 return 0;
120 }
121 buf[n] = 0;
122 return 1;
123 }
124
125 static char *
sysfs_deref_link(struct pci_dev * d,char * link_name)126 sysfs_deref_link(struct pci_dev *d, char *link_name)
127 {
128 char path[2*OBJNAMELEN], rel_path[OBJNAMELEN];
129
130 sysfs_obj_name(d, link_name, path);
131 memset(rel_path, 0, sizeof(rel_path));
132
133 if (readlink(path, rel_path, sizeof(rel_path)) < 0)
134 return NULL;
135
136 sysfs_obj_name(d, "", path);
137 strcat(path, rel_path);
138
139 // Returns a pointer to malloc'ed memory
140 return realpath(path, NULL);
141 }
142
143 static int
sysfs_get_value(struct pci_dev * d,char * object,int mandatory)144 sysfs_get_value(struct pci_dev *d, char *object, int mandatory)
145 {
146 char buf[OBJBUFSIZE];
147
148 if (sysfs_get_string(d, object, buf, mandatory))
149 return strtol(buf, NULL, 0);
150 else
151 return -1;
152 }
153
154 static void
sysfs_get_resources(struct pci_dev * d)155 sysfs_get_resources(struct pci_dev *d)
156 {
157 struct pci_access *a = d->access;
158 char namebuf[OBJNAMELEN], buf[256];
159 struct { pciaddr_t flags, base_addr, size; } lines[10];
160 int have_bar_bases, have_rom_base, have_bridge_bases;
161 FILE *file;
162 int i;
163
164 have_bar_bases = have_rom_base = have_bridge_bases = 0;
165 sysfs_obj_name(d, "resource", namebuf);
166 file = fopen(namebuf, "r");
167 if (!file)
168 a->error("Cannot open %s: %s", namebuf, strerror(errno));
169 for (i = 0; i < 7+6+4+1; i++)
170 {
171 unsigned long long start, end, size, flags;
172 if (!fgets(buf, sizeof(buf), file))
173 break;
174 if (sscanf(buf, "%llx %llx %llx", &start, &end, &flags) != 3)
175 a->error("Syntax error in %s", namebuf);
176 if (end > start)
177 size = end - start + 1;
178 else
179 size = 0;
180 if (i < 6)
181 {
182 d->flags[i] = flags;
183 flags &= PCI_ADDR_FLAG_MASK;
184 d->base_addr[i] = start | flags;
185 d->size[i] = size;
186 have_bar_bases = 1;
187 }
188 else if (i == 6)
189 {
190 d->rom_flags = flags;
191 flags &= PCI_ADDR_FLAG_MASK;
192 d->rom_base_addr = start | flags;
193 d->rom_size = size;
194 have_rom_base = 1;
195 }
196 else if (i < 7+6+4)
197 {
198 /*
199 * If kernel was compiled without CONFIG_PCI_IOV option then after
200 * the ROM line for configured bridge device (that which had set
201 * subordinary bus number to non-zero value) are four additional lines
202 * which describe resources behind bridge. For PCI-to-PCI bridges they
203 * are: IO, MEM, PREFMEM and empty. For CardBus bridges they are: IO0,
204 * IO1, MEM0 and MEM1. For unconfigured bridges and other devices
205 * there is no additional line after the ROM line. If kernel was
206 * compiled with CONFIG_PCI_IOV option then after the ROM line and
207 * before the first bridge resource line are six additional lines
208 * which describe IOV resources. Read all remaining lines in resource
209 * file and based on the number of remaining lines (0, 4, 6, 10) parse
210 * resources behind bridge.
211 */
212 lines[i-7].flags = flags;
213 lines[i-7].base_addr = start;
214 lines[i-7].size = size;
215 }
216 }
217 if (i == 7+4 || i == 7+6+4)
218 {
219 int offset = (i == 7+6+4) ? 6 : 0;
220 for (i = 0; i < 4; i++)
221 {
222 d->bridge_flags[i] = lines[offset+i].flags;
223 d->bridge_base_addr[i] = lines[offset+i].base_addr;
224 d->bridge_size[i] = lines[offset+i].size;
225 }
226 have_bridge_bases = 1;
227 }
228 fclose(file);
229 if (!have_bar_bases)
230 clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS);
231 if (!have_rom_base)
232 clear_fill(d, PCI_FILL_ROM_BASE);
233 if (!have_bridge_bases)
234 clear_fill(d, PCI_FILL_BRIDGE_BASES);
235 }
236
sysfs_scan(struct pci_access * a)237 static void sysfs_scan(struct pci_access *a)
238 {
239 char dirname[1024];
240 DIR *dir;
241 struct dirent *entry;
242 int n;
243
244 n = snprintf(dirname, sizeof(dirname), "%s/devices", sysfs_name(a));
245 if (n < 0 || n >= (int) sizeof(dirname))
246 a->error("Directory name too long");
247 dir = opendir(dirname);
248 if (!dir)
249 a->error("Cannot open %s", dirname);
250 while ((entry = readdir(dir)))
251 {
252 struct pci_dev *d;
253 unsigned int dom, bus, dev, func;
254
255 /* ".", ".." or a special non-device perhaps */
256 if (entry->d_name[0] == '.')
257 continue;
258
259 d = pci_alloc_dev(a);
260 if (sscanf(entry->d_name, "%x:%x:%x.%d", &dom, &bus, &dev, &func) < 4)
261 a->error("sysfs_scan: Couldn't parse entry name %s", entry->d_name);
262
263 /* Ensure kernel provided domain that fits in a signed integer */
264 if (dom > 0x7fffffff)
265 a->error("sysfs_scan: Invalid domain %x", dom);
266
267 d->domain = dom;
268 d->bus = bus;
269 d->dev = dev;
270 d->func = func;
271 pci_link_dev(a, d);
272 }
273 closedir(dir);
274 }
275
276 static void
sysfs_fill_slots(struct pci_access * a)277 sysfs_fill_slots(struct pci_access *a)
278 {
279 char dirname[1024];
280 DIR *dir;
281 struct dirent *entry;
282 int n;
283
284 n = snprintf(dirname, sizeof(dirname), "%s/slots", sysfs_name(a));
285 if (n < 0 || n >= (int) sizeof(dirname))
286 a->error("Directory name too long");
287 dir = opendir(dirname);
288 if (!dir)
289 return;
290
291 while (entry = readdir(dir))
292 {
293 char namebuf[OBJNAMELEN], buf[16];
294 FILE *file;
295 unsigned int dom, bus, dev;
296 int res = 0;
297 struct pci_dev *d;
298
299 /* ".", ".." or a special non-device perhaps */
300 if (entry->d_name[0] == '.')
301 continue;
302
303 n = snprintf(namebuf, OBJNAMELEN, "%s/%s/%s", dirname, entry->d_name, "address");
304 if (n < 0 || n >= OBJNAMELEN)
305 a->error("File name too long");
306 file = fopen(namebuf, "r");
307 /*
308 * Old versions of Linux had a fakephp which didn't have an 'address'
309 * file. There's no useful information to be gleaned from these
310 * devices, pretend they're not there.
311 */
312 if (!file)
313 continue;
314
315 if (!fgets(buf, sizeof(buf), file) || (res = sscanf(buf, "%x:%x:%x", &dom, &bus, &dev)) < 3)
316 {
317 /*
318 * In some cases, the slot is not tied to a specific device before
319 * a card gets inserted. This happens for example on IBM pSeries
320 * and we need not warn about it.
321 */
322 if (res != 2)
323 a->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf);
324 }
325 else
326 {
327 for (d = a->devices; d; d = d->next)
328 if (dom == (unsigned)d->domain && bus == d->bus && dev == d->dev && !d->phy_slot)
329 d->phy_slot = pci_set_property(d, PCI_FILL_PHYS_SLOT, entry->d_name);
330 }
331 fclose(file);
332 }
333 closedir(dir);
334 }
335
336 static void
sysfs_fill_info(struct pci_dev * d,unsigned int flags)337 sysfs_fill_info(struct pci_dev *d, unsigned int flags)
338 {
339 int value, want_class, want_class_ext;
340
341 if (!d->access->buscentric)
342 {
343 /*
344 * These fields can be read from the config registers, but we want to show
345 * the kernel's view, which has regions and IRQs remapped and other fields
346 * (most importantly classes) possibly fixed if the device is known broken.
347 */
348 if (want_fill(d, flags, PCI_FILL_IDENT))
349 {
350 d->vendor_id = sysfs_get_value(d, "vendor", 1);
351 d->device_id = sysfs_get_value(d, "device", 1);
352 }
353 want_class = want_fill(d, flags, PCI_FILL_CLASS);
354 want_class_ext = want_fill(d, flags, PCI_FILL_CLASS_EXT);
355 if (want_class || want_class_ext)
356 {
357 value = sysfs_get_value(d, "class", 1);
358 if (want_class)
359 d->device_class = value >> 8;
360 if (want_class_ext)
361 {
362 d->prog_if = value & 0xff;
363 value = sysfs_get_value(d, "revision", 0);
364 if (value < 0)
365 value = pci_read_byte(d, PCI_REVISION_ID);
366 if (value >= 0)
367 d->rev_id = value;
368 }
369 }
370 if (want_fill(d, flags, PCI_FILL_SUBSYS))
371 {
372 value = sysfs_get_value(d, "subsystem_vendor", 0);
373 if (value >= 0)
374 {
375 d->subsys_vendor_id = value;
376 value = sysfs_get_value(d, "subsystem_device", 0);
377 if (value >= 0)
378 d->subsys_id = value;
379 }
380 else
381 clear_fill(d, PCI_FILL_SUBSYS);
382 }
383 if (want_fill(d, flags, PCI_FILL_IRQ))
384 d->irq = sysfs_get_value(d, "irq", 1);
385 if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS | PCI_FILL_BRIDGE_BASES))
386 sysfs_get_resources(d);
387 if (want_fill(d, flags, PCI_FILL_PARENT))
388 {
389 unsigned int domain, bus, dev, func;
390 char *path_abs, *path_canon, *name;
391 char path_rel[OBJNAMELEN];
392 struct pci_dev *parent;
393
394 /* Construct sysfs path for parent device */
395 sysfs_obj_name(d, "..", path_rel);
396 path_abs = realpath(path_rel, NULL);
397 name = path_abs ? strrchr(path_abs, '/') : NULL;
398 name = name ? name+1 : name;
399 parent = NULL;
400
401 if (name && sscanf(name, "%x:%x:%x.%d", &domain, &bus, &dev, &func) == 4 && domain <= 0x7fffffff)
402 for (parent = d->access->devices; parent; parent = parent->next)
403 if (parent->domain == (int)domain && parent->bus == bus && parent->dev == dev && parent->func == func)
404 break;
405
406 if (parent)
407 {
408 /* Check if parsed BDF address from parent sysfs device is really expected PCI device */
409 sysfs_obj_name(parent, ".", path_rel);
410 path_canon = realpath(path_rel, NULL);
411 if (!path_canon || strcmp(path_canon, path_abs) != 0)
412 parent = NULL;
413
414 if (path_canon)
415 free(path_canon);
416 }
417
418 if (parent)
419 d->parent = parent;
420 else
421 clear_fill(d, PCI_FILL_PARENT);
422
423 if (path_abs)
424 free(path_abs);
425 }
426 }
427
428 if (want_fill(d, flags, PCI_FILL_PHYS_SLOT))
429 {
430 struct pci_dev *pd;
431 sysfs_fill_slots(d->access);
432 for (pd = d->access->devices; pd; pd = pd->next)
433 pd->known_fields |= PCI_FILL_PHYS_SLOT;
434 }
435
436 if (want_fill(d, flags, PCI_FILL_MODULE_ALIAS))
437 {
438 char buf[OBJBUFSIZE];
439 if (sysfs_get_string(d, "modalias", buf, 0))
440 d->module_alias = pci_set_property(d, PCI_FILL_MODULE_ALIAS, buf);
441 }
442
443 if (want_fill(d, flags, PCI_FILL_LABEL))
444 {
445 char buf[OBJBUFSIZE];
446 if (sysfs_get_string(d, "label", buf, 0))
447 d->label = pci_set_property(d, PCI_FILL_LABEL, buf);
448 }
449
450 if (want_fill(d, flags, PCI_FILL_NUMA_NODE))
451 d->numa_node = sysfs_get_value(d, "numa_node", 0);
452
453 if (want_fill(d, flags, PCI_FILL_IOMMU_GROUP))
454 {
455 char *group_link = sysfs_deref_link(d, "iommu_group");
456 if (group_link)
457 {
458 pci_set_property(d, PCI_FILL_IOMMU_GROUP, basename(group_link));
459 free(group_link);
460 }
461 }
462
463 if (want_fill(d, flags, PCI_FILL_DT_NODE))
464 {
465 char *node = sysfs_deref_link(d, "of_node");
466 if (node)
467 {
468 pci_set_property(d, PCI_FILL_DT_NODE, node);
469 free(node);
470 }
471 }
472
473 if (want_fill(d, flags, PCI_FILL_DRIVER))
474 {
475 char *driver_path = sysfs_deref_link(d, "driver");
476 if (driver_path)
477 {
478 char *driver = strrchr(driver_path, '/');
479 driver = driver ? driver+1 : driver_path;
480 pci_set_property(d, PCI_FILL_DRIVER, driver);
481 free(driver_path);
482 }
483 else
484 clear_fill(d, PCI_FILL_DRIVER);
485 }
486
487 if (want_fill(d, flags, PCI_FILL_RCD_LNK))
488 {
489 char buf[OBJBUFSIZE];
490 if (sysfs_get_string(d, "rcd_link_cap", buf, 0))
491 d->rcd_link_cap = strtoul(buf, NULL, 16);
492 if (sysfs_get_string(d, "rcd_link_ctrl", buf, 0))
493 d->rcd_link_ctrl = strtoul(buf, NULL, 16);
494 if (sysfs_get_string(d, "rcd_link_status", buf, 0))
495 d->rcd_link_status = strtoul(buf, NULL, 16);
496 }
497
498 pci_generic_fill_info(d, flags);
499 }
500
501 /* Intent of the sysfs_setup() caller */
502 enum
503 {
504 SETUP_READ_CONFIG = 0,
505 SETUP_WRITE_CONFIG = 1,
506 SETUP_READ_VPD = 2
507 };
508
509 static int
sysfs_setup(struct pci_dev * d,int intent)510 sysfs_setup(struct pci_dev *d, int intent)
511 {
512 struct pci_access *a = d->access;
513 char namebuf[OBJNAMELEN];
514
515 if (a->cached_dev != d || (intent == SETUP_WRITE_CONFIG && !a->fd_rw))
516 {
517 sysfs_flush_cache(a);
518 a->cached_dev = d;
519 }
520
521 if (intent == SETUP_READ_VPD)
522 {
523 if (a->fd_vpd < 0)
524 {
525 sysfs_obj_name(d, "vpd", namebuf);
526 a->fd_vpd = open(namebuf, O_RDONLY);
527 /* No warning on error; vpd may be absent or accessible only to root */
528 }
529 return a->fd_vpd;
530 }
531
532 if (a->fd < 0)
533 {
534 sysfs_obj_name(d, "config", namebuf);
535 a->fd_rw = a->writeable || intent == SETUP_WRITE_CONFIG;
536 a->fd = open(namebuf, a->fd_rw ? O_RDWR : O_RDONLY);
537 if (a->fd < 0)
538 a->warning("Cannot open %s", namebuf);
539 }
540 return a->fd;
541 }
542
sysfs_read(struct pci_dev * d,int pos,byte * buf,int len)543 static int sysfs_read(struct pci_dev *d, int pos, byte *buf, int len)
544 {
545 int fd = sysfs_setup(d, SETUP_READ_CONFIG);
546 int res;
547
548 if (fd < 0)
549 return 0;
550 res = pread(fd, buf, len, pos);
551 if (res < 0)
552 {
553 d->access->warning("sysfs_read: read failed: %s", strerror(errno));
554 return 0;
555 }
556 else if (res != len)
557 return 0;
558 return 1;
559 }
560
sysfs_write(struct pci_dev * d,int pos,byte * buf,int len)561 static int sysfs_write(struct pci_dev *d, int pos, byte *buf, int len)
562 {
563 int fd = sysfs_setup(d, SETUP_WRITE_CONFIG);
564 int res;
565
566 if (fd < 0)
567 return 0;
568 res = pwrite(fd, buf, len, pos);
569 if (res < 0)
570 {
571 d->access->warning("sysfs_write: write failed: %s", strerror(errno));
572 return 0;
573 }
574 else if (res != len)
575 {
576 d->access->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len, pos, res);
577 return 0;
578 }
579 return 1;
580 }
581
sysfs_read_vpd(struct pci_dev * d,int pos,byte * buf,int len)582 static int sysfs_read_vpd(struct pci_dev *d, int pos, byte *buf, int len)
583 {
584 int fd = sysfs_setup(d, SETUP_READ_VPD);
585 int res;
586
587 if (fd < 0)
588 return 0;
589 res = pread(fd, buf, len, pos);
590 if (res < 0)
591 {
592 d->access->warning("sysfs_read_vpd: read failed: %s", strerror(errno));
593 return 0;
594 }
595 else if (res != len)
596 return 0;
597 return 1;
598 }
599
sysfs_cleanup_dev(struct pci_dev * d)600 static void sysfs_cleanup_dev(struct pci_dev *d)
601 {
602 struct pci_access *a = d->access;
603
604 if (a->cached_dev == d)
605 sysfs_flush_cache(a);
606 }
607
608 struct pci_methods pm_linux_sysfs = {
609 .name = "linux-sysfs",
610 .help = "The sys filesystem on Linux",
611 .config = sysfs_config,
612 .detect = sysfs_detect,
613 .init = sysfs_init,
614 .cleanup = sysfs_cleanup,
615 .scan = sysfs_scan,
616 .fill_info = sysfs_fill_info,
617 .read = sysfs_read,
618 .write = sysfs_write,
619 .read_vpd = sysfs_read_vpd,
620 .cleanup_dev = sysfs_cleanup_dev,
621 };
622