2 * The PCI Library -- Configuration Access via /sys/bus/pci
4 * Copyright (c) 2003 Matthew Wilcox <matthew@wil.cx>
5 * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
7 * Can be freely distributed and used under the terms of the GNU GPL.
20 #include <sys/types.h>
26 sysfs_config(struct pci_access
*a
)
28 pci_define_param(a
, "sysfs.path", PCI_PATH_SYS_BUS_PCI
, "Path to the sysfs device tree");
32 sysfs_name(struct pci_access
*a
)
34 return pci_get_param(a
, "sysfs.path");
38 sysfs_detect(struct pci_access
*a
)
40 if (access(sysfs_name(a
), R_OK
))
42 a
->debug("...cannot open %s", sysfs_name(a
));
45 a
->debug("...using %s", sysfs_name(a
));
50 sysfs_init(struct pci_access
*a
)
57 sysfs_flush_cache(struct pci_access
*a
)
73 sysfs_cleanup(struct pci_access
*a
)
78 #define OBJNAMELEN 1024
80 sysfs_obj_name(struct pci_dev
*d
, char *object
, char *buf
)
82 int n
= snprintf(buf
, OBJNAMELEN
, "%s/devices/%04x:%02x:%02x.%d/%s",
83 sysfs_name(d
->access
), d
->domain
, d
->bus
, d
->dev
, d
->func
, object
);
84 if (n
< 0 || n
>= OBJNAMELEN
)
85 d
->access
->error("File name too long");
88 #define OBJBUFSIZE 1024
91 sysfs_get_string(struct pci_dev
*d
, char *object
, char *buf
, int mandatory
)
93 struct pci_access
*a
= d
->access
;
95 char namebuf
[OBJNAMELEN
];
96 void (*warn
)(char *msg
, ...) = (mandatory
? a
->error
: a
->warning
);
98 sysfs_obj_name(d
, object
, namebuf
);
99 fd
= open(namebuf
, O_RDONLY
);
102 if (mandatory
|| errno
!= ENOENT
)
103 warn("Cannot open %s: %s", namebuf
, strerror(errno
));
106 n
= read(fd
, buf
, OBJBUFSIZE
);
110 warn("Error reading %s: %s", namebuf
, strerror(errno
));
115 warn("Value in %s too long", namebuf
);
123 sysfs_get_value(struct pci_dev
*d
, char *object
, int mandatory
)
125 char buf
[OBJBUFSIZE
];
127 if (sysfs_get_string(d
, object
, buf
, mandatory
))
128 return strtol(buf
, NULL
, 0);
134 sysfs_get_resources(struct pci_dev
*d
)
136 struct pci_access
*a
= d
->access
;
137 char namebuf
[OBJNAMELEN
], buf
[256];
141 sysfs_obj_name(d
, "resource", namebuf
);
142 file
= fopen(namebuf
, "r");
144 a
->error("Cannot open %s: %s", namebuf
, strerror(errno
));
145 for (i
= 0; i
< 7; i
++)
147 unsigned long long start
, end
, size
, flags
;
148 if (!fgets(buf
, sizeof(buf
), file
))
150 if (sscanf(buf
, "%llx %llx %llx", &start
, &end
, &flags
) != 3)
151 a
->error("Syntax error in %s", namebuf
);
153 size
= end
- start
+ 1;
159 flags
&= PCI_ADDR_FLAG_MASK
;
160 d
->base_addr
[i
] = start
| flags
;
165 d
->rom_flags
= flags
;
166 flags
&= PCI_ADDR_FLAG_MASK
;
167 d
->rom_base_addr
= start
| flags
;
174 static void sysfs_scan(struct pci_access
*a
)
178 struct dirent
*entry
;
181 n
= snprintf(dirname
, sizeof(dirname
), "%s/devices", sysfs_name(a
));
182 if (n
< 0 || n
>= (int) sizeof(dirname
))
183 a
->error("Directory name too long");
184 dir
= opendir(dirname
);
186 a
->error("Cannot open %s", dirname
);
187 while ((entry
= readdir(dir
)))
190 unsigned int dom
, bus
, dev
, func
;
192 /* ".", ".." or a special non-device perhaps */
193 if (entry
->d_name
[0] == '.')
196 d
= pci_alloc_dev(a
);
197 if (sscanf(entry
->d_name
, "%x:%x:%x.%d", &dom
, &bus
, &dev
, &func
) < 4)
198 a
->error("sysfs_scan: Couldn't parse entry name %s", entry
->d_name
);
200 /* Ensure kernel provided domain that fits in a signed integer */
201 if (dom
> 0x7fffffff)
202 a
->error("sysfs_scan: Invalid domain %x", dom
);
210 sysfs_get_resources(d
);
211 d
->irq
= sysfs_get_value(d
, "irq", 1);
213 * We could read these faster from the config registers, but we want to give
214 * the kernel a chance to fix up ID's and especially classes of broken devices.
216 d
->vendor_id
= sysfs_get_value(d
, "vendor", 1);
217 d
->device_id
= sysfs_get_value(d
, "device", 1);
218 d
->device_class
= sysfs_get_value(d
, "class", 1) >> 8;
219 d
->known_fields
= PCI_FILL_IDENT
| PCI_FILL_CLASS
| PCI_FILL_IRQ
| PCI_FILL_BASES
| PCI_FILL_ROM_BASE
| PCI_FILL_SIZES
| PCI_FILL_IO_FLAGS
;
227 sysfs_fill_slots(struct pci_access
*a
)
231 struct dirent
*entry
;
234 n
= snprintf(dirname
, sizeof(dirname
), "%s/slots", sysfs_name(a
));
235 if (n
< 0 || n
>= (int) sizeof(dirname
))
236 a
->error("Directory name too long");
237 dir
= opendir(dirname
);
241 while (entry
= readdir(dir
))
243 char namebuf
[OBJNAMELEN
], buf
[16];
245 unsigned int dom
, bus
, dev
;
249 /* ".", ".." or a special non-device perhaps */
250 if (entry
->d_name
[0] == '.')
253 n
= snprintf(namebuf
, OBJNAMELEN
, "%s/%s/%s", dirname
, entry
->d_name
, "address");
254 if (n
< 0 || n
>= OBJNAMELEN
)
255 a
->error("File name too long");
256 file
= fopen(namebuf
, "r");
258 * Old versions of Linux had a fakephp which didn't have an 'address'
259 * file. There's no useful information to be gleaned from these
260 * devices, pretend they're not there.
265 if (!fgets(buf
, sizeof(buf
), file
) || (res
= sscanf(buf
, "%x:%x:%x", &dom
, &bus
, &dev
)) < 3)
268 * In some cases, the slot is not tied to a specific device before
269 * a card gets inserted. This happens for example on IBM pSeries
270 * and we need not warn about it.
273 a
->warning("sysfs_fill_slots: Couldn't parse entry address %s", buf
);
277 for (d
= a
->devices
; d
; d
= d
->next
)
278 if (dom
== (unsigned)d
->domain
&& bus
== d
->bus
&& dev
== d
->dev
&& !d
->phy_slot
)
279 d
->phy_slot
= pci_strdup(a
, entry
->d_name
);
287 sysfs_fill_info(struct pci_dev
*d
, int flags
)
289 if ((flags
& PCI_FILL_PHYS_SLOT
) && !(d
->known_fields
& PCI_FILL_PHYS_SLOT
))
292 sysfs_fill_slots(d
->access
);
293 for (pd
= d
->access
->devices
; pd
; pd
= pd
->next
)
294 pd
->known_fields
|= PCI_FILL_PHYS_SLOT
;
297 if ((flags
& PCI_FILL_MODULE_ALIAS
) && !(d
->known_fields
& PCI_FILL_MODULE_ALIAS
))
299 char buf
[OBJBUFSIZE
];
300 if (sysfs_get_string(d
, "modalias", buf
, 0))
301 d
->module_alias
= pci_strdup(d
->access
, buf
);
304 if ((flags
& PCI_FILL_LABEL
) && !(d
->known_fields
& PCI_FILL_LABEL
))
306 char buf
[OBJBUFSIZE
];
307 if (sysfs_get_string(d
, "label", buf
, 0))
308 d
->label
= pci_strdup(d
->access
, buf
);
311 if ((flags
& PCI_FILL_NUMA_NODE
) && !(d
->known_fields
& PCI_FILL_NUMA_NODE
))
312 d
->numa_node
= sysfs_get_value(d
, "numa_node", 0);
314 return pci_generic_fill_info(d
, flags
);
317 /* Intent of the sysfs_setup() caller */
320 SETUP_READ_CONFIG
= 0,
321 SETUP_WRITE_CONFIG
= 1,
326 sysfs_setup(struct pci_dev
*d
, int intent
)
328 struct pci_access
*a
= d
->access
;
329 char namebuf
[OBJNAMELEN
];
331 if (a
->cached_dev
!= d
|| (intent
== SETUP_WRITE_CONFIG
&& !a
->fd_rw
))
333 sysfs_flush_cache(a
);
337 if (intent
== SETUP_READ_VPD
)
341 sysfs_obj_name(d
, "vpd", namebuf
);
342 a
->fd_vpd
= open(namebuf
, O_RDONLY
);
343 /* No warning on error; vpd may be absent or accessible only to root */
350 sysfs_obj_name(d
, "config", namebuf
);
351 a
->fd_rw
= a
->writeable
|| intent
== SETUP_WRITE_CONFIG
;
352 a
->fd
= open(namebuf
, a
->fd_rw
? O_RDWR
: O_RDONLY
);
354 a
->warning("Cannot open %s", namebuf
);
360 static int sysfs_read(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
362 int fd
= sysfs_setup(d
, SETUP_READ_CONFIG
);
367 res
= do_read(d
, fd
, buf
, len
, pos
);
370 d
->access
->warning("sysfs_read: read failed: %s", strerror(errno
));
378 static int sysfs_write(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
380 int fd
= sysfs_setup(d
, SETUP_WRITE_CONFIG
);
385 res
= do_write(d
, fd
, buf
, len
, pos
);
388 d
->access
->warning("sysfs_write: write failed: %s", strerror(errno
));
393 d
->access
->warning("sysfs_write: tried to write %d bytes at %d, but only %d succeeded", len
, pos
, res
);
399 #ifdef PCI_HAVE_DO_READ
401 /* pread() is not available and do_read() only works for a single fd, so we
402 * cannot implement read_vpd properly. */
403 static int sysfs_read_vpd(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
408 #else /* !PCI_HAVE_DO_READ */
410 static int sysfs_read_vpd(struct pci_dev
*d
, int pos
, byte
*buf
, int len
)
412 int fd
= sysfs_setup(d
, SETUP_READ_VPD
);
417 res
= pread(fd
, buf
, len
, pos
);
420 d
->access
->warning("sysfs_read_vpd: read failed: %s", strerror(errno
));
428 #endif /* PCI_HAVE_DO_READ */
430 static void sysfs_cleanup_dev(struct pci_dev
*d
)
432 struct pci_access
*a
= d
->access
;
434 if (a
->cached_dev
== d
)
435 sysfs_flush_cache(a
);
438 struct pci_methods pm_linux_sysfs
= {
440 "The sys filesystem on Linux",