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