2
* Copyright (c) 2006-2010 Dell, Inc.
3
* by Matt Domsch <Matt_Domsch@dell.com>
4
* Licensed under the GNU General Public license, version 2.
20
#include "dmidecode/dmidecode.h"
23
static int read_pci_sysfs_path(char *buf, size_t bufsize, const struct pci_dev *pdev)
28
unparse_pci_name(pci_name, sizeof(pci_name), pdev);
29
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s", pci_name);
30
size = readlink(path, buf, bufsize);
36
static int read_pci_sysfs_physfn(char *buf, size_t bufsize, const struct pci_dev *pdev)
41
unparse_pci_name(pci_name, sizeof(pci_name), pdev);
42
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/physfn", pci_name);
43
size = readlink(path, buf, bufsize);
49
static int virtfn_filter(const struct dirent *dent)
51
return (!strncmp(dent->d_name,"virtfn",6));
54
static int _read_virtfn_index(unsigned int *index, const char *path, const char *basename, const char *pci_name)
56
char buf[PATH_MAX], *b;
57
char fullpath[PATH_MAX];
59
unsigned int u=INT_MAX;
62
snprintf(fullpath, sizeof(fullpath), "%s/%s", path, basename);
63
size = readlink(fullpath, buf, sizeof(buf));
65
/* form is ../0000:05:10.0 */
66
b=buf+3; /* skip ../ */
67
if (strlen(b) == strlen(pci_name) &&
68
!strncmp(b, pci_name, strlen(pci_name))) {
69
scanned = sscanf(basename, "virtfn%u", &u);
79
static int read_virtfn_index(unsigned int *index, const struct pci_dev *pdev)
84
struct dirent **namelist;
87
unparse_pci_name(pci_name, sizeof(pci_name), pdev);
88
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/physfn", pci_name);
89
if (realpath(path, cpath) == NULL)
92
n = scandir(cpath, &namelist, virtfn_filter, versionsort);
98
rc = _read_virtfn_index(index, cpath, namelist[n]->d_name, pci_name);
107
static int parse_pci_name(const char *s, int *domain, int *bus, int *dev, int *func)
110
/* The domain part was added in 2.6 kernels. Test for that first. */
111
err = sscanf(s, "%x:%2x:%2x.%x", domain, bus, dev, func);
113
err = sscanf(s, "%2x:%2x.%x", bus, dev, func);
121
static struct pci_dev * find_pdev_by_pci_name(struct pci_access *pacc, const char *s)
123
int domain=0, bus=0, device=0, func=0;
124
if (parse_pci_name(s, &domain, &bus, &device, &func))
126
return pci_get_dev(pacc, domain, bus, device, func);
129
static struct pci_device *
130
find_physfn(struct libbiosdevname_state *state, struct pci_device *dev)
135
struct pci_dev *pdev;
136
memset(path, 0, sizeof(path));
137
rc = read_pci_sysfs_physfn(path, sizeof(path), dev->pci_dev);
140
/* we get back a string like
142
where the last component is the parent device
144
/* find the last backslash */
145
c = rindex(path, '/');
147
pdev = find_pdev_by_pci_name(state->pacc, c);
148
dev = find_dev_by_pci(state, pdev);
152
static int is_same_pci(const struct pci_dev *a, const struct pci_dev *b)
154
if (pci_domain_nr(a) == pci_domain_nr(b) &&
162
static void try_add_vf_to_pf(struct libbiosdevname_state *state, struct pci_device *vf)
164
struct pci_device *pf;
165
unsigned int index=0;
167
pf = find_physfn(state, vf);
171
list_add_tail(&vf->vfnode, &pf->vfs);
172
rc = read_virtfn_index(&index, vf->pci_dev);
174
vf->vf_index = index;
175
pf->is_sriov_physical_function = 1;
178
vf->physical_slot = pf->physical_slot;
181
static struct pci_device *
182
find_parent(struct libbiosdevname_state *state, struct pci_device *dev)
187
struct pci_device *physfn;
188
struct pci_dev *pdev;
189
memset(path, 0, sizeof(path));
190
/* if this device has a physfn pointer, then treat _that_ as the parent */
191
physfn = find_physfn(state, dev);
193
dev->is_sriov_virtual_function=1;
197
rc = read_pci_sysfs_path(path, sizeof(path), dev->pci_dev);
200
/* we get back a string like
201
../../../devices/pci0000:00/0000:00:09.0/0000:05:17.4
202
where the last component is the device we asked for
204
/* find the last backslash */
205
c = rindex(path, '/');
207
/* find the last backslash again */
208
c = rindex(path, '/');
210
pdev = find_pdev_by_pci_name(state->pacc, c);
212
dev = find_dev_by_pci(state, pdev);
219
* Check our parents in case the device itself isn't listed
220
* in the SMBIOS table. This has a problem, as
221
* our parent bridge on a card may not be included
222
* in the SMBIOS table. In that case, it falls back to "unknown".
224
static inline int pci_dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev)
226
return dev->physical_slot;
229
static inline int pirq_dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev)
231
return pirq_pci_dev_to_slot(state->pirq_table, pci_domain_nr(dev->pci_dev), dev->pci_dev->bus, dev->pci_dev->dev);
234
static void dev_to_slot(struct libbiosdevname_state *state, struct pci_device *dev)
236
struct pci_device *d = dev;
239
slot = pci_dev_to_slot(state, d);
240
if (slot == PHYSICAL_SLOT_UNKNOWN)
241
slot = pirq_dev_to_slot(state, d);
242
if (slot == PHYSICAL_SLOT_UNKNOWN)
243
d = find_parent(state, d);
244
} while (d && slot == PHYSICAL_SLOT_UNKNOWN);
246
dev->physical_slot = slot;
249
static char *read_pci_sysfs_label(const struct pci_dev *pdev)
256
unparse_pci_name(pci_name, sizeof(pci_name), pdev);
257
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/label", pci_name);
258
rc = sysfs_read_file(path, &label);
264
static int read_pci_sysfs_index(unsigned int *index, const struct pci_dev *pdev)
269
char *indexstr = NULL;
271
unparse_pci_name(pci_name, sizeof(pci_name), pdev);
272
snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/index", pci_name);
273
rc = sysfs_read_file(path, &indexstr);
275
rc = sscanf(indexstr, "%u", &i);
284
static void fill_pci_dev_sysfs(struct pci_device *dev, struct pci_dev *p)
287
unsigned int index = 0;
290
unparse_pci_name(buf, sizeof(buf), p);
291
rc = read_pci_sysfs_index(&index, p);
293
dev->sysfs_index = index;
294
dev->uses_sysfs |= HAS_SYSFS_INDEX;
296
label = read_pci_sysfs_label(p);
298
dev->sysfs_label = label;
299
dev->uses_sysfs |= HAS_SYSFS_LABEL;
303
static void add_pci_dev(struct libbiosdevname_state *state,
306
struct pci_device *dev;
307
dev = malloc(sizeof(*dev));
309
fprintf(stderr, "out of memory\n");
312
memset(dev, 0, sizeof(*dev));
313
INIT_LIST_HEAD(&dev->node);
314
INIT_LIST_HEAD(&dev->vfnode);
315
INIT_LIST_HEAD(&dev->vfs);
317
dev->physical_slot = PHYSICAL_SLOT_UNKNOWN;
318
dev->class = pci_read_word(p, PCI_CLASS_DEVICE);
319
dev->vf_index = INT_MAX;
320
fill_pci_dev_sysfs(dev, p);
321
list_add(&dev->node, &state->pci_devices);
324
void free_pci_devices(struct libbiosdevname_state *state)
326
struct pci_device *pos, *next;
327
list_for_each_entry_safe(pos, next, &state->pci_devices, node) {
328
if (pos->smbios_label)
329
free(pos->smbios_label);
330
if (pos->sysfs_label)
331
free(pos->sysfs_label);
332
list_del(&pos->node);
337
static void set_pci_slots(struct libbiosdevname_state *state)
339
struct pci_device *dev;
341
list_for_each_entry(dev, &state->pci_devices, node) {
342
dev_to_slot(state, dev);
347
static int set_pci_slot_index(struct libbiosdevname_state *state)
349
struct pci_device *pcidev;
353
/* only iterate over the PCI devices, because the bios_device list may be incomplete due to renames happening in parallel */
354
list_for_each_entry(pcidev, &state->pci_devices, node) {
355
if (pcidev->physical_slot == 0) /* skip embedded devices */
357
if (!is_pci_network(pcidev)) /* only look at PCI network devices */
359
if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */
361
if (pcidev->physical_slot != prevslot) {
363
prevslot = pcidev->physical_slot;
367
pcidev->index_in_slot = index;
372
static int set_embedded_index(struct libbiosdevname_state *state)
374
struct pci_device *pcidev;
377
list_for_each_entry(pcidev, &state->pci_devices, node) {
378
if (pcidev->physical_slot != 0) /* skip non-embedded devices */
380
if (!is_pci_network(pcidev)) /* only look at PCI network devices */
382
if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */
384
pcidev->embedded_index = index;
385
pcidev->embedded_index_valid = 1;
391
static void set_sriov_pf_vf(struct libbiosdevname_state *state)
393
struct pci_device *vf;
394
list_for_each_entry(vf, &state->pci_devices, node) {
395
if (!vf->is_sriov_virtual_function)
397
try_add_vf_to_pf(state, vf);
402
* This sorts the PCI devices by breadth-first domain/bus/dev/fn.
404
static int sort_pci(const struct pci_device *a, const struct pci_device *b)
407
if (pci_domain_nr(a->pci_dev) < pci_domain_nr(b->pci_dev)) return -1;
408
else if (pci_domain_nr(a->pci_dev) > pci_domain_nr(b->pci_dev)) return 1;
410
if (a->pci_dev->bus < b->pci_dev->bus) return -1;
411
else if (a->pci_dev->bus > b->pci_dev->bus) return 1;
413
if (a->pci_dev->dev < b->pci_dev->dev) return -1;
414
else if (a->pci_dev->dev > b->pci_dev->dev) return 1;
416
if (a->pci_dev->func < b->pci_dev->func) return -1;
417
else if (a->pci_dev->func > b->pci_dev->func) return 1;
422
static void insertion_sort_devices(struct pci_device *a, struct list_head *list,
423
int (*cmp)(const struct pci_device *, const struct pci_device *))
425
struct pci_device *b;
426
list_for_each_entry(b, list, node) {
427
if (cmp(a, b) <= 0) {
428
list_move_tail(&a->node, &b->node);
432
list_move_tail(&a->node, list);
435
static void sort_device_list(struct libbiosdevname_state *state)
437
LIST_HEAD(sorted_devices);
438
struct pci_device *dev, *tmp;
439
list_for_each_entry_safe(dev, tmp, &state->pci_devices, node) {
440
insertion_sort_devices(dev, &sorted_devices, sort_pci);
442
list_splice(&sorted_devices, &state->pci_devices);
445
int get_pci_devices(struct libbiosdevname_state *state)
447
struct pci_access *pacc;
449
struct routing_table *table;
452
table = pirq_alloc_read_table();
454
state->pirq_table = table;
463
for (p=pacc->devices; p; p=p->next) {
464
add_pci_dev(state, p);
466
/* ordering here is important */
467
dmidecode_main(state); /* this will fail on Xen guests, that's OK */
468
sort_device_list(state);
469
set_pci_slots(state);
470
set_embedded_index(state);
471
set_pci_slot_index(state);
472
set_sriov_pf_vf(state);
477
int unparse_pci_name(char *buf, int size, const struct pci_dev *pdev)
479
return snprintf(buf, size, "%04x:%02x:%02x.%x",
480
pci_domain_nr(pdev), pdev->bus, pdev->dev, pdev->func);
483
static int unparse_location(char *buf, const int size, const int location)
487
s += snprintf(s, size-(s-buf), "embedded");
488
else if (location == INT_MAX)
489
s += snprintf(s, size-(s-buf), "unknown");
490
else if (location > 0)
491
s += snprintf(s, size-(s-buf), "%u", location);
493
s += snprintf(s, size-(s-buf), "unknown");
497
static int unparse_smbios_type41_type(char *buf, const int size, const int type)
500
const char *msg[] = {"Other",
511
if (type > 0 && type <= sizeof(msg))
512
s += snprintf(s, size-(s-buf), "%s\n", msg[type-1]);
514
s += snprintf(s, size-(s-buf), "<OUT OF SPEC>\n");
518
int unparse_pci_device(char *buf, const int size, const struct pci_device *p)
521
struct pci_device *dev;
523
s += snprintf(s, size-(s-buf), "PCI name : ");
524
s += unparse_pci_name(s, size-(s-buf), p->pci_dev);
525
s += snprintf(s, size-(s-buf), "\n");
526
s += snprintf(s, size-(s-buf), "PCI Slot : ");
527
if (p->physical_slot < INT_MAX)
528
s += unparse_location(s, size-(s-buf), p->physical_slot);
530
s += snprintf(s, size-(s-buf), "Unknown");
531
s += snprintf(s, size-(s-buf), "\n");
532
if (p->smbios_type) {
533
s += snprintf(s, size-(s-buf), "SMBIOS Device Type: ");
534
s += unparse_smbios_type41_type(s, size-(s-buf), p->smbios_type);
535
s += snprintf(s, size-(s-buf), "SMBIOS Instance: %u\n", p->smbios_instance);
536
s += snprintf(s, size-(s-buf), "SMBIOS Enabled: %s\n", p->smbios_instance?"True":"False");
538
if (p->uses_smbios & HAS_SMBIOS_LABEL && p->smbios_label)
539
s += snprintf(s, size-(s-buf), "SMBIOS Label: %s\n", p->smbios_label);
540
if (p->uses_sysfs & HAS_SYSFS_INDEX)
541
s += snprintf(s, size-(s-buf), "sysfs Index: %u\n", p->sysfs_index);
542
if (p->uses_sysfs & HAS_SYSFS_LABEL)
543
s += snprintf(s, size-(s-buf), "sysfs Label: %s\n", p->sysfs_label);
544
if (p->physical_slot > 0 && !p->is_sriov_virtual_function)
545
s += snprintf(s, size-(s-buf), "Index in slot: %u\n", p->index_in_slot);
546
if (p->embedded_index_valid)
547
s += snprintf(s, size-(s-buf), "Embedded Index: %u\n", p->embedded_index);
549
if (!list_empty(&p->vfs)) {
550
s += snprintf(s, size-(s-buf), "Virtual Functions:\n");
551
list_for_each_entry(dev, &p->vfs, vfnode) {
552
unparse_pci_name(pci_name, sizeof(pci_name), dev->pci_dev);
553
s += snprintf(s, size-(s-buf), "%s\n", pci_name);
560
struct pci_device * find_dev_by_pci(const struct libbiosdevname_state *state,
561
const struct pci_dev *p)
563
struct pci_device *dev;
564
list_for_each_entry(dev, &state->pci_devices, node) {
565
if (is_same_pci(p, dev->pci_dev))
571
struct pci_device * find_pci_dev_by_pci_addr(const struct libbiosdevname_state *state,
572
const int domain, const int bus, const int device, const int func)
574
struct pci_device *dev;
576
memset(&p, 0, sizeof(p));
578
#ifdef HAVE_STRUCT_PCI_DEV_DOMAIN
585
list_for_each_entry(dev, &state->pci_devices, node) {
586
if (is_same_pci(&p, dev->pci_dev))
592
struct pci_device * find_dev_by_pci_name(const struct libbiosdevname_state *state,
595
int domain=0, bus=0, device=0, func=0;
596
if (parse_pci_name(s, &domain, &bus, &device, &func))
599
return find_pci_dev_by_pci_addr(state, domain, bus, device, func);