diff --git a/Makefile.am b/Makefile.am index 28d3e8d..14d9a92 100644 --- a/Makefile.am +++ b/Makefile.am @@ -6,7 +6,7 @@ dist_noinst_DATA = biosdevname.rules.in biosdevname.spec.fedora biosdevname.spec -CLEANFILES = version src/version.h +CLEANFILES = version src/bios_dev_name.h install-data-local: mkdir -p $(DESTDIR)@RULEDIR@ $(INSTALL_DATA) $(top_srcdir)/biosdevname.rules.in $(DESTDIR)@RULEDEST@ diff --git a/biosdevname.1 b/biosdevname.1 index 7067a56..22a53bd 100644 --- a/biosdevname.1 +++ b/biosdevname.1 @@ -31,16 +31,16 @@ Treat [args] as ethernet devs .B \-d, \-\-debug Enable debugging .TP -.B \-\-policy \fI[physical|all_ethN] +.B \-p, \-\-policy \fI[physical|all_ethN] .TP -.B \-\-prefix \fI[string] +.B \-P, \-\-prefix \fI[string] string use for embedded NICs in the physical policy (default=em) .TP -.B \-\-nopirq +.B \-x, \-\-nopirq Do not use $PIR table for mapping PCI device to slot. Some BIOS have incorrect values. .TP -.B \-\-smbios \fI[x.y] +.B \-s, \-\-smbios \fI[x.y] Require minimum SMBIOS version x.y .SH POLICIES .br diff --git a/configure.ac b/configure.ac index e26ba98..d08d42f 100644 --- a/configure.ac +++ b/configure.ac @@ -3,7 +3,7 @@ # vim:tw=0:ts=8:sw=8:et AC_PREREQ(2.59) -AC_INIT([biosdevname],[0.5.0],[Jordan_Hargrave@dell.com]) +AC_INIT([biosdevname],[0.5.1],[Jordan_Hargrave@dell.com]) AC_LANG([C]) AC_USE_SYSTEM_EXTENSIONS AC_CONFIG_SRCDIR([src/read_proc.c]) @@ -88,5 +88,5 @@ echo "PACKAGE_NAME='$PACKAGE_NAME'" > version echo "PACKAGE_VERSION='$PACKAGE_VERSION'" >> version echo "PACKAGE_STRING='$PACKAGE_STRING'" >> version -AC_CONFIG_FILES([Makefile biosdevname.spec.fedora biosdevname.spec.suse src/version.h]) +AC_CONFIG_FILES([Makefile biosdevname.spec.fedora biosdevname.spec.suse src/bios_dev_name.h]) AC_OUTPUT diff --git a/src/bios_dev_name.c b/src/bios_dev_name.c index 7374f9b..d0a917a 100644 --- a/src/bios_dev_name.c +++ b/src/bios_dev_name.c @@ -10,8 +10,6 @@ #include #include -#include "version.h" - #include "libbiosdevname.h" #include "bios_dev_name.h" @@ -27,11 +25,11 @@ static void usage(void) fprintf(stderr, " Options:\n"); fprintf(stderr, " -i or --interface treat [args] as ethernet devs\n"); fprintf(stderr, " -d or --debug enable debugging\n"); - fprintf(stderr, " --policy [physical | all_ethN ]\n"); - fprintf(stderr, " --prefix [string] string use for embedded NICs (default='em')\n"); - fprintf(stderr, " --smbios [x.y] Require SMBIOS x.y or greater\n"); - fprintf(stderr, " --nopirq Don't use $PIR table for slot numbers\n"); - fprintf(stderr, " --version Show biosdevname version\n"); + fprintf(stderr, " -p or --policy [physical | all_ethN ]\n"); + fprintf(stderr, " -P or --prefix [string] string use for embedded NICs (default='em')\n"); + fprintf(stderr, " -s or --smbios [x.y] Require SMBIOS x.y or greater\n"); + fprintf(stderr, " -x or --nopirq Don't use $PIR table for slot numbers\n"); + fprintf(stderr, " -v or --version Show biosdevname version\n"); fprintf(stderr, " Example: biosdevname -i eth0\n"); fprintf(stderr, " returns: em1\n"); fprintf(stderr, " when eth0 is an embedded NIC with label '1' on the chassis.\n"); @@ -70,7 +68,7 @@ parse_opts(int argc, char **argv) {0, 0, 0, 0} }; c = getopt_long(argc, argv, - "dinp:", + "dip:P:xs:v", long_options, &option_index); if (c == -1) break; diff --git a/src/bios_dev_name.h b/src/bios_dev_name.h deleted file mode 100644 index 636c5e1..0000000 --- a/src/bios_dev_name.h +++ /dev/null @@ -1,20 +0,0 @@ -/* - * Copyright (c) 2006 Dell, Inc. - * by Matt Domsch - * Licensed under the GNU General Public license, version 2. - */ -#ifndef GLUE_H_INCLUDED -#define GLUE_H_INCLUDED - -struct bios_dev_name_opts { - int argc; - char **argv; - int optind; - int sortroutine; - int namingpolicy; - const char *prefix; - unsigned int debug:1; - unsigned int interface:1; -}; - -#endif /* GLUE_H_INCLUDED */ diff --git a/src/bios_dev_name.h.in b/src/bios_dev_name.h.in new file mode 100644 index 0000000..444c5e5 --- /dev/null +++ b/src/bios_dev_name.h.in @@ -0,0 +1,22 @@ +/* + * Copyright (c) 2006 Dell, Inc. + * by Matt Domsch + * Licensed under the GNU General Public license, version 2. + */ +#ifndef GLUE_H_INCLUDED +#define GLUE_H_INCLUDED + +#define BIOSDEVNAME_VERSION "@PACKAGE_VERSION@" + +struct bios_dev_name_opts { + int argc; + char **argv; + int optind; + int sortroutine; + int namingpolicy; + const char *prefix; + unsigned int debug:1; + unsigned int interface:1; +}; + +#endif /* GLUE_H_INCLUDED */ diff --git a/src/bios_device.c b/src/bios_device.c index 9e319a3..ba0661f 100644 --- a/src/bios_device.c +++ b/src/bios_device.c @@ -212,33 +212,17 @@ static void sort_device_list(struct libbiosdevname_state *state) list_splice(&sorted_devices, &state->bios_devices); } -static void match_pci_and_eth_devs(struct libbiosdevname_state *state) +/* Check for Mellanox/Chelsio drivers */ +int ismultiport(const char *driver) { - struct pci_device *p; - struct bios_device *b; - struct network_device *n; - - list_for_each_entry(n, &state->network_devices, node) { - p = find_dev_by_pci_name(state, n->drvinfo.bus_info); - if (!p) - continue; - - b = malloc(sizeof(*b)); - if (!b) - continue; - memset(b, 0, sizeof(*b)); - INIT_LIST_HEAD(&b->node); - b->pcidev = p; - b->netdev = n; - b->slot_num = -1; - b->port_num = -1; - claim_netdev(b->netdev); - list_add(&b->node, &state->bios_devices); - } + if (!strncmp(driver, "mlx", 3)) + return 1; + if (!strncmp(driver, "cxgb", 4)) + return 1; + return 0; } - -static void match_eth_and_pci_devs(struct libbiosdevname_state *state) +static void match_pci_and_eth_devs(struct libbiosdevname_state *state) { struct pci_device *p; struct bios_device *b; @@ -249,22 +233,30 @@ static void match_eth_and_pci_devs(struct libbiosdevname_state *state) if (!is_pci_network(p)) continue; + /* Loop through all ether devices to find match */ unparse_pci_name(pci_name, sizeof(pci_name), p->pci_dev); - n = find_net_device_by_bus_info(state, pci_name); - if (!n) - continue; - - b = malloc(sizeof(*b)); - if (!b) - continue; - memset(b, 0, sizeof(*b)); - INIT_LIST_HEAD(&b->node); - b->pcidev = p; - b->netdev = n; - b->slot_num = -1; - b->port_num = -1; - claim_netdev(b->netdev); - list_add(&b->node, &state->bios_devices); + list_for_each_entry(n, &state->network_devices, node) { + if (strncmp(n->drvinfo.bus_info, pci_name, sizeof(n->drvinfo.bus_info))) + continue; + b = malloc(sizeof(*b)); + if (!b) + continue; + memset(b, 0, sizeof(*b)); + INIT_LIST_HEAD(&b->node); + b->pcidev = p; + b->netdev = n; + b->port = NULL; + if (ismultiport(n->drvinfo.driver)) { + b->port = malloc(sizeof(struct pci_port)); + if (b->port != NULL) { + b->port->port = n->devid+1; + b->port->pfi = p->is_sriov_virtual_function ? + p->vf_index : -1; + } + } + claim_netdev(b->netdev); + list_add(&b->node, &state->bios_devices); + } } } @@ -286,8 +278,7 @@ static void match_unknown_eths(struct libbiosdevname_state *state) memset(b, 0, sizeof(*b)); INIT_LIST_HEAD(&b->node); b->netdev = n; - b->slot_num = -1; - b->port_num = -1; + b->port = NULL; list_add(&b->node, &state->bios_devices); } } @@ -355,26 +346,6 @@ static void find_duplicates(struct libbiosdevname_state *state) } } -extern int addslot(struct libbiosdevname_state *state, int slot); - -/* Fix for RHBZ 816536/757743/756164/: Cards with same PCI but multiple ports - * chelsio, mellanox */ -static void check_ports(struct libbiosdevname_state *state) -{ - struct pci_device *dev; - struct bios_device *a; - - list_for_each_entry(a, &state->bios_devices, node) { - dev = a->pcidev; - if (dev == NULL || dev->is_sriov_virtual_function || dev->vpd_port != INT_MAX) - continue; - if (dev->physical_slot != PHYSICAL_SLOT_UNKNOWN) { - a->slot_num = dev->physical_slot; - a->port_num = addslot(state, 0x1000 + dev->physical_slot); - } - } -} - void * setup_bios_devices(int namingpolicy, const char *prefix) { int rc=1; @@ -390,7 +361,6 @@ void * setup_bios_devices(int namingpolicy, const char *prefix) get_eths(state); match_all(state); sort_device_list(state); - check_ports(state); rc = assign_bios_network_names(state, namingpolicy, prefix); if (rc) goto out; diff --git a/src/bios_device.h b/src/bios_device.h index d1ef911..158a2af 100644 --- a/src/bios_device.h +++ b/src/bios_device.h @@ -12,16 +12,15 @@ #include "pci.h" #include "naming_policy.h" +struct pci_port; struct bios_device { struct list_head node; struct network_device *netdev; struct pci_device *pcidev; char *bios_name; + struct pci_port *port; int duplicate; - - int slot_num; - int port_num; }; static inline int is_pci(const struct bios_device *dev) diff --git a/src/dmidecode/dmidecode.c b/src/dmidecode/dmidecode.c index 3f761a9..f766b8c 100644 --- a/src/dmidecode/dmidecode.c +++ b/src/dmidecode/dmidecode.c @@ -119,14 +119,15 @@ int smbios_setslot(const struct libbiosdevname_state *state, struct pci_device *pdev, *n; int i; - dprintf("setslot: %.4x:%.2x:%.2x.%x = slot(%2d %2d) %s\n", - domain, bus, device, func, slot, index, label); + dprintf("setslot: %.4x:%.2x:%.2x.%x = type:%x slot(%2d %2d) %s\n", + domain, bus, device, func, type, slot, index, label); /* Don't bother with disabled devices */ - if ((bus == 0 && device == 0 && func == 0) || /* bug on HP systems */ + if ((domain == 0xFFFF) || + (bus == 0 && device == 0 && func == 0) || /* bug on HP systems */ (bus == 0xFF && device == 0x1F && func == 0x7)) { - dprintf("disabled\n"); + dprintf(" disabled\n"); return; } @@ -153,18 +154,11 @@ int smbios_setslot(const struct libbiosdevname_state *state, } /* Found a PDEV, now is it a bridge? */ - if (pdev->sbus == -1) - continue; - dprintf("scan subbus: %d\n", pdev->sbus); - list_for_each_entry(n, &state->pci_devices, node) { - if (matchpci(n, domain, pdev->sbus, -1, -1)) { - smbios_setslot(state, n->pci_dev->domain, n->pci_dev->bus, - n->pci_dev->dev, n->pci_dev->func, - type, slot, index, label); - } + if (pdev->sbus != -1) { + smbios_setslot(state, domain, pdev->sbus, -1, -1, type, slot, index, label); } - dprintf("done subbus: %d\n", pdev->sbus); } + return 0; } static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevname_state *state) @@ -179,12 +173,9 @@ static void dmi_decode(struct dmi_header *h, u16 ver, const struct libbiosdevnam bus = data[0x0F]; device = (data[0x10]>>3)&0x1F; function = data[0x10] & 7; - if (domain != 0xFFFF) { - for (i=0; i<8; i++) - smbios_setslot(state, domain, bus, device, i, - 0x00, WORD(data+0x09), 0x00, - dmi_string(h, data[0x04])); - } + smbios_setslot(state, domain, bus, device, -1, + 0x00, WORD(data+0x09), 0x00, + dmi_string(h, data[0x04])); } else { dprintf("Old Slot: id:%3d, type:%.2x, label:%-7s\n", WORD(data+0x09), data[0x05], dmi_string(h, data[0x04])); @@ -361,6 +352,57 @@ static int address_from_efi(size_t *address) static const char *devmem = "/dev/mem"; +int dmidecode_read_file(const struct libbiosdevname_state *state) +{ +#ifdef _JPH + FILE *fp; + const char *dmidecode_file = "dmidecode.txt"; + char line[128], *r; + int type = -1, eth=0,s,b,d,f,slot,i; + + if ((fp = fopen(dmidecode_file, "r")) == NULL) + return 0; + while ((fgets(line, sizeof(line), fp)) != NULL) { + if (strstr(line, " DMI type 41,") != NULL) { + type = 41; + eth = 0; + slot = -1; + } else if (strstr(line, " DMI type 9,") != NULL) { + type = 9; + } else if (strstr(line, " DMI type ") != NULL) { + type = -1; + } + if (type == 41) { + if ((r = strstr(line, "Type: Ethernet")) != NULL) { + eth = 1; + } + if ((r = strstr(line, "Type Instance: ")) != NULL) { + sscanf(r, "Type Instance: %d", &slot); + } + if ((r = strstr(line, "Bus Address: ")) != NULL && eth) { + sscanf(r, "Bus Address: %x:%x:%x.%x", &s,&b,&d,&f); + printf("bus: %.4x:%.2x:%.2x.%x\n", s, b, d, f); + smbios_setslot(state, s, b, d, f, 0x5, 0x00, slot, ""); + } + } + if (type == 9) { + /* System Slots */ + if ((r = strstr(line, "ID: ")) != NULL) { + sscanf(r, "ID: %d", &slot); + } + if ((r = strstr(line, "Bus Address: ")) != NULL) { + sscanf(r, "Bus Address: %x:%x:%x.%x", &s,&b,&d,&f); + printf("bus: %.4x:%.2x:%.2x.%x = %d\n", s, b, d, f, slot); + for (i=0; i<8; i++) + smbios_setslot(state, s, b, d, i, 0x00, slot, 0x00, ""); + } + } + } + return 1; +#endif + return 0; +} + int dmidecode_main(const struct libbiosdevname_state *state) { int ret=0; /* Returned value */ @@ -369,6 +411,9 @@ int dmidecode_main(const struct libbiosdevname_state *state) int efi; u8 *buf; + if (dmidecode_read_file(state)) + return 0; + /* First try EFI (ia64, Intel-based Mac) */ efi=address_from_efi(&fp); switch(efi) diff --git a/src/eths.c b/src/eths.c index bcd02e1..38bb7fe 100644 --- a/src/eths.c +++ b/src/eths.c @@ -34,6 +34,20 @@ char *pr_ether(char *buf, const int size, const unsigned char *s) return (buf); } +static int eths_get_devid(const char *devname, int *devid) +{ + char path[PATH_MAX]; + char *devidstr = NULL; + + *devid = -1; + snprintf(path, sizeof(path), "/sys/class/net/%s/dev_id", devname); + if (sysfs_read_file(path, &devidstr) == 0) { + sscanf(devidstr, "%i", devid); + free(devidstr); + } + return NULL; +} + static int eths_get_ifindex(const char *devname, int *ifindex) { int fd, err; @@ -149,6 +163,7 @@ static void fill_eth_dev(struct network_device *dev) eths_get_ifindex(dev->kernel_name, &dev->ifindex); eths_get_hwaddr(dev->kernel_name, dev->dev_addr, sizeof(dev->dev_addr), &dev->arphrd_type); eths_get_permaddr(dev->kernel_name, dev->perm_addr, sizeof(dev->perm_addr)); + eths_get_devid(dev->kernel_name, &dev->devid); rc = eths_get_info(dev->kernel_name, &dev->drvinfo); if (rc == 0) dev->drvinfo_valid = 1; diff --git a/src/eths.h b/src/eths.h index f686136..12c278b 100644 --- a/src/eths.h +++ b/src/eths.h @@ -27,6 +27,7 @@ struct network_device { int arphrd_type; /* e.g. ARPHDR_ETHER */ int hardware_claimed; /* true when recognized as PCI or PCMCIA and added to list of bios_devices */ int ifindex; + int devid; }; extern void get_eths(struct libbiosdevname_state *state); diff --git a/src/naming_policy.c b/src/naming_policy.c index fe7b934..7138a4b 100644 --- a/src/naming_policy.c +++ b/src/naming_policy.c @@ -55,12 +55,14 @@ static void use_physical(const struct libbiosdevname_state *state, const char *p vf = vf->vpd_pf; if (vf->pf) vf = vf->pf; - if (vf->uses_sysfs & HAS_SYSFS_INDEX) + if (dev->port) + portnum = dev->port->port; + else if (vf->uses_sysfs & HAS_SYSFS_INDEX) portnum = vf->sysfs_index; else if (vf->uses_smbios & HAS_SMBIOS_INSTANCE && is_pci_smbios_type_ethernet(vf)) portnum = vf->smbios_instance; - else if (dev->port_num != -1) - portnum = dev->port_num; + else if (vf->embedded_index_valid) + portnum = vf->embedded_index; if (portnum != INT_MAX) { snprintf(location, sizeof(location), "%s%u", prefix, portnum); known=1; @@ -68,10 +70,10 @@ static void use_physical(const struct libbiosdevname_state *state, const char *p } else if (dev->pcidev->physical_slot < PHYSICAL_SLOT_UNKNOWN) { snprintf(location, sizeof(location), "p%u", dev->pcidev->physical_slot); - if (dev->pcidev->vpd_port < INT_MAX) + if (dev->port) + portnum = dev->port->port; + else if (dev->pcidev->vpd_port < INT_MAX) portnum = dev->pcidev->vpd_port; - else if (dev->port_num != -1) - portnum = dev->port_num; else if (!dev->pcidev->is_sriov_virtual_function) portnum = dev->pcidev->index_in_slot; else @@ -80,7 +82,9 @@ static void use_physical(const struct libbiosdevname_state *state, const char *p known=1; } - if (dev->pcidev->is_sriov_virtual_function) + if (dev->port && dev->port->pfi != -1) + snprintf(interface, sizeof(interface), "_%u", dev->port->pfi); + else if (dev->pcidev->is_sriov_virtual_function) snprintf(interface, sizeof(interface), "_%u", dev->pcidev->vf_index); else if (dev->pcidev->vpd_pfi < INT_MAX) snprintf(interface, sizeof(interface), "_%u", dev->pcidev->vpd_pfi); diff --git a/src/pci.c b/src/pci.c index d017c50..7a7cb36 100644 --- a/src/pci.c +++ b/src/pci.c @@ -30,6 +30,7 @@ extern int is_valid_smbios; /* Borrowed from kernel vpd code */ #define PCI_VPD_LRDT 0x80 #define PCI_VPD_SRDT_END 0x78 +#define PCI_VPDR_TAG 0x90 #define PCI_VPD_SRDT_LEN_MASK 0x7 #define PCI_VPD_LRDT_TAG_SIZE 3 @@ -71,7 +72,7 @@ static int pci_vpd_size(struct pci_device *pdev, int fd) tag = buf[0] & ~PCI_VPD_SRDT_LEN_MASK; off += PCI_VPD_SRDT_TAG_SIZE + pci_vpd_srdt_size(buf); } - if (tag == 0 || tag == 0xFF || tag == PCI_VPD_SRDT_END) + if (tag == 0 || tag == 0xFF || tag == PCI_VPD_SRDT_END || tag == PCI_VPDR_TAG) break; } return off; @@ -120,12 +121,31 @@ static int pci_vpd_find_info_subkey(const u8 *buf, unsigned int off, unsigned in return -1; } +/* Add port identifier(s) to PCI device */ +static void add_port(struct pci_device *pdev, int port, int pfi) +{ + struct pci_port *p; + + list_for_each_entry(p, &pdev->ports, node) { + if (p->port == port && p->pfi == pfi) + return; + } + p = malloc(sizeof(*p)); + if (p == NULL) + return; + memset(p, 0, sizeof(*p)); + INIT_LIST_HEAD(&p->node); + p->port = port; + p->pfi = pfi; + list_add_tail(&p->node, &pdev->ports); +} + static int parse_vpd(struct libbiosdevname_state *state, struct pci_device *pdev, int len, unsigned char *vpd) { int i, j, k, isz, jsz, port, func, pfi; struct pci_device *vf; - i = pci_vpd_find_tag(vpd, 0, len, 0x90); + i = pci_vpd_find_tag(vpd, 0, len, PCI_VPDR_TAG); if (i < 0) return 1; isz = pci_vpd_lrdt_size(&vpd[i]); @@ -154,6 +174,7 @@ static int parse_vpd(struct libbiosdevname_state *state, struct pci_device *pdev pdev->pci_dev->bus, pdev->pci_dev->dev, func)) != NULL) { + add_port(vf, port, pfi); if (vf->vpd_port == INT_MAX) { vf->vpd_port = port; vf->vpd_pfi = pfi; @@ -324,67 +345,15 @@ static int read_pci_sysfs_physfn(char *buf, size_t bufsize, const struct pci_dev return 0; } -static int virtfn_filter(const struct dirent *dent) -{ - return (!strncmp(dent->d_name,"virtfn",6)); -} - -static int _read_virtfn_index(unsigned int *index, const char *path, const char *basename, const char *pci_name) -{ - char buf[PATH_MAX], *b; - char fullpath[PATH_MAX]; - ssize_t size; - unsigned int u=INT_MAX; - int scanned, rc=1; - - snprintf(fullpath, sizeof(fullpath), "%s/%s", path, basename); - size = readlink(fullpath, buf, sizeof(buf)); - if (size > 0) { - /* form is ../0000:05:10.0 */ - b=buf+3; /* skip ../ */ - if (strlen(b) == strlen(pci_name) && - !strncmp(b, pci_name, strlen(pci_name))) { - scanned = sscanf(basename, "virtfn%u", &u); - if (scanned == 1) { - rc = 0; - *index = u; - } - } - } - return rc; -} - -static int read_virtfn_index(unsigned int *index, const struct pci_dev *pdev) -{ - char pci_name[16]; - char path[PATH_MAX]; - char cpath[PATH_MAX]; - struct dirent **namelist; - int n, rc=1; - - unparse_pci_name(pci_name, sizeof(pci_name), pdev); - snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/physfn", pci_name); - if (realpath(path, cpath) == NULL) - return rc; - - n = scandir(cpath, &namelist, virtfn_filter, versionsort); - if (n < 0) - return rc; - else { - while (n--) { - if (rc) - rc = _read_virtfn_index(index, cpath, namelist[n]->d_name, pci_name); - free(namelist[n]); - } - free(namelist); - } - - return rc; -} - static int parse_pci_name(const char *s, int *domain, int *bus, int *dev, int *func) { int err; + const char *r; + + /* Allow parsing pathnames */ + if ((r = strrchr(s, '/')) != NULL) + s = r+1; + /* The domain part was added in 2.6 kernels. Test for that first. */ err = sscanf(s, "%x:%2x:%2x.%x", domain, bus, dev, func); if (err != 4) { @@ -404,29 +373,6 @@ static struct pci_dev * find_pdev_by_pci_name(struct pci_access *pacc, const cha return pci_get_dev(pacc, domain, bus, device, func); } -static struct pci_device * -find_physfn(struct libbiosdevname_state *state, struct pci_device *dev) -{ - int rc; - char path[PATH_MAX]; - char *c; - struct pci_dev *pdev; - memset(path, 0, sizeof(path)); - rc = read_pci_sysfs_physfn(path, sizeof(path), dev->pci_dev); - if (rc != 0) - return NULL; - /* we get back a string like - ../0000:05:0.0 - where the last component is the parent device - */ - /* find the last backslash */ - c = rindex(path, '/'); - c++; - pdev = find_pdev_by_pci_name(state->pacc, c); - dev = find_dev_by_pci(state, pdev); - return dev; -} - static int is_same_pci(const struct pci_dev *a, const struct pci_dev *b) { if (pci_domain_nr(a) == pci_domain_nr(b) && @@ -437,25 +383,6 @@ static int is_same_pci(const struct pci_dev *a, const struct pci_dev *b) return 0; } -static void try_add_vf_to_pf(struct libbiosdevname_state *state, struct pci_device *vf) -{ - struct pci_device *pf; - unsigned int index=0; - int rc; - pf = find_physfn(state, vf); - - if (!pf) - return; - list_add_tail(&vf->vfnode, &pf->vfs); - rc = read_virtfn_index(&index, vf->pci_dev); - if (!rc) { - vf->vf_index = index; - pf->is_sriov_physical_function = 1; - } - vf->pf = pf; - vf->physical_slot = pf->physical_slot; -} - static struct pci_device * find_parent(struct libbiosdevname_state *state, struct pci_device *dev) { @@ -465,12 +392,6 @@ find_parent(struct libbiosdevname_state *state, struct pci_device *dev) struct pci_device *physfn; struct pci_dev *pdev; memset(path, 0, sizeof(path)); - /* if this device has a physfn pointer, then treat _that_ as the parent */ - physfn = find_physfn(state, dev); - if (physfn) { - dev->is_sriov_virtual_function=1; - return physfn; - } rc = read_pci_sysfs_path(path, sizeof(path), dev->pci_dev); if (rc != 0) @@ -553,6 +474,7 @@ static int read_pci_sysfs_index(unsigned int *index, const struct pci_dev *pdev) rc = sysfs_read_file(path, &indexstr); if (rc == 0) { rc = sscanf(indexstr, "%u", &i); + free(indexstr); if (rc == 1) { *index = i; return 0; @@ -595,6 +517,7 @@ static void add_pci_dev(struct libbiosdevname_state *state, INIT_LIST_HEAD(&dev->node); INIT_LIST_HEAD(&dev->vfnode); INIT_LIST_HEAD(&dev->vfs); + INIT_LIST_HEAD(&dev->ports); dev->pci_dev = p; dev->physical_slot = PHYSICAL_SLOT_UNKNOWN; dev->class = pci_read_word(p, PCI_CLASS_DEVICE); @@ -631,24 +554,6 @@ void free_pci_devices(struct libbiosdevname_state *state) } } -int addslot(struct libbiosdevname_state *state, int slot) -{ - struct slotlist *s; - - list_for_each_entry(s, &state->slots, node) { - if (s->slot == slot) { - return ++s->count; - } - } - s = malloc(sizeof(*s)); - INIT_LIST_HEAD(&s->node); - s->slot = slot; - s->count = 0; - list_add(&s->node, &state->slots); - - return ++s->count; -} - static void set_pci_slots(struct libbiosdevname_state *state) { struct pci_device *dev; @@ -656,28 +561,105 @@ static void set_pci_slots(struct libbiosdevname_state *state) list_for_each_entry(dev, &state->pci_devices, node) { dev_to_slot(state, dev); } +} - /* Get mapping for each slot */ - list_for_each_entry(dev, &state->pci_devices, node) { - if (dev->is_sriov_virtual_function || !is_pci_network(dev) || dev->vpd_port != INT_MAX) { +static int set_pci_slot_index(struct libbiosdevname_state *state) +{ + struct pci_device *pcidev; + int prevslot=-1; + int index=1; + + /* only iterate over the PCI devices, because the bios_device list may be incomplete due to renames happening in parallel */ + list_for_each_entry(pcidev, &state->pci_devices, node) { + if (pcidev->physical_slot == 0) /* skip embedded devices */ continue; + if (!is_pci_network(pcidev)) /* only look at PCI network devices */ + continue; + if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */ + continue; + if (pcidev->physical_slot != prevslot) { + index=1; + prevslot = pcidev->physical_slot; } - if (dev->physical_slot == 0) { - dev->embedded_index_valid = 1; - dev->embedded_index = addslot(state, 0); - } else if (dev->physical_slot != PHYSICAL_SLOT_UNKNOWN) { - dev->index_in_slot = addslot(state, dev->physical_slot); - } + else + index++; + pcidev->index_in_slot = index; + } + return 0; +} + +static int set_embedded_index(struct libbiosdevname_state *state) +{ + struct pci_device *pcidev; + int index=1; + + list_for_each_entry(pcidev, &state->pci_devices, node) { + if (pcidev->physical_slot != 0) /* skip non-embedded devices */ + continue; + if (!is_pci_network(pcidev)) /* only look at PCI network devices */ + continue; + if (pcidev->is_sriov_virtual_function) /* skip sriov VFs, they're handled later */ + continue; + if (pcidev->vpd_port != INT_MAX) + continue; + pcidev->embedded_index = index; + pcidev->embedded_index_valid = 1; + index++; } + return 0; } -static void set_sriov_pf_vf(struct libbiosdevname_state *state) +static int virtfn_filter(const struct dirent *dent) +{ + return (!strncmp(dent->d_name,"virtfn",6)); +} + +/* Assign Virtual Function to Physical Function */ +static void set_sriov(struct libbiosdevname_state *state, struct pci_device *pf, const char *virtpath) { struct pci_device *vf; - list_for_each_entry(vf, &state->pci_devices, node) { - if (!vf->is_sriov_virtual_function) + char pci_name[32]; + char path[PATH_MAX], cpath[PATH_MAX]; + int vf_index; + + if (sscanf(virtpath, "virtfn%u", &vf_index) != 1) + return; + unparse_pci_name(pci_name, sizeof(pci_name), pf->pci_dev); + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s/%s", pci_name, virtpath); + + memset(cpath, 0, sizeof(cpath)); + if (readlink(path, cpath, sizeof(cpath)) < 0) + return; + if ((vf = find_dev_by_pci_name(state, cpath)) != NULL) { + vf->is_sriov_virtual_function = 1; + vf->vf_index = vf_index; + vf->pf = pf; + pf->is_sriov_physical_function = 1; + list_add_tail(&vf->vfnode, &pf->vfs); + } +} + +static void scan_sriov(struct libbiosdevname_state *state) +{ + struct pci_device *pf; + char path[PATH_MAX]; + char pci_name[32]; + struct dirent **namelist; + int n; + + list_for_each_entry(pf, &state->pci_devices, node) { + unparse_pci_name(pci_name, sizeof(pci_name), pf->pci_dev); + snprintf(path, sizeof(path), "/sys/bus/pci/devices/%s", pci_name); + + namelist = NULL; + n = scandir(path, &namelist, virtfn_filter, versionsort); + if (n <= 0) continue; - try_add_vf_to_pf(state, vf); + while (n--) { + set_sriov(state, pf, namelist[n]->d_name); + free(namelist[n]); + } + free(namelist); } } @@ -753,9 +735,11 @@ int get_pci_devices(struct libbiosdevname_state *state) /* ordering here is important */ dmidecode_main(state); /* this will fail on Xen guests, that's OK */ sort_device_list(state); + scan_sriov(state); set_pci_vpd_instance(state); set_pci_slots(state); - set_sriov_pf_vf(state); + set_embedded_index(state); + set_pci_slot_index(state); return rc; } diff --git a/src/pci.h b/src/pci.h index 77b4746..eacb539 100644 --- a/src/pci.h +++ b/src/pci.h @@ -20,6 +20,12 @@ struct slotlist int count; }; +struct pci_port { + struct list_head node; + int port; + int pfi; +}; + struct pci_device { struct list_head node; struct pci_dev *pci_dev; @@ -44,6 +50,7 @@ struct pci_device { struct pci_device *pf; struct list_head vfnode; struct list_head vfs; + struct list_head ports; unsigned int is_sriov_physical_function:1; unsigned int is_sriov_virtual_function:1; unsigned int embedded_index_valid:1; diff --git a/src/pirq.c b/src/pirq.c index 6568c24..0aa4d0c 100644 --- a/src/pirq.c +++ b/src/pirq.c @@ -44,7 +44,53 @@ int pirq_pci_dev_to_slot(struct routing_table *table, int domain, int bus, int d return INT_MAX; } +struct routing_table *pirq_read_file() +{ +#ifdef _JPH + FILE *fp; + char line[128]; + struct routing_table *table; + char *r; + int count, bus, dev, slot; + const char *pirq_file = "biosdecode.txt"; + /* Get count of entries */ + if ((fp = fopen(pirq_file, "r")) == NULL) + return NULL; + count = 0; + while (fgets(line, sizeof(line), fp) != NULL) { + if (strstr(line, "Slot Entry") != NULL) + count++; + } + fclose(fp); + + /* Read table */ + table = malloc(sizeof(*table) + count * sizeof(struct slot_entry)); + table->size = 32 + (sizeof(struct slot_entry) * count); + if ((fp = fopen(pirq_file, "r")) == NULL) + return NULL; + count = 0; + while (fgets(line, sizeof(line), fp) != NULL) { + if ((r = strstr(line, "Slot Entry")) == NULL) + continue; + if (sscanf(r, "Slot Entry %*d: ID %x:%x", &bus, &dev) == 2) { + table->slot[count].bus = bus; + table->slot[count].device = dev << 3; + if ((r = strstr(line, "on-board")) != NULL) + table->slot[count].slot = 0; + else if ((r = strstr(line, "slot number ")) != NULL) { + sscanf(r, "slot number %d", &slot); + table->slot[count].slot = slot; + } + printf("%d = %.2x:%.2x = %d\n", count, bus, dev, table->slot[count].slot); + count++; + } + } + fclose(fp); + return table; +#endif + return NULL; +} struct routing_table * pirq_alloc_read_table() { @@ -60,6 +106,9 @@ struct routing_table * pirq_alloc_read_table() if (nopirq) { return NULL; } + if ((table = pirq_read_file()) != NULL) + return table; + fd = open("/dev/mem", O_RDONLY); if(fd==-1) return NULL; diff --git a/src/sysfs.c b/src/sysfs.c index 71e84e7..e276240 100644 --- a/src/sysfs.c +++ b/src/sysfs.c @@ -32,7 +32,7 @@ int sysfs_path_is_file(const char * path) int sysfs_read_file(const char * path, char **output) { int ret; - char *result = NULL; + char *result = NULL, *n; int fd; unsigned long resultsize = 0; ssize_t length = 0; @@ -57,8 +57,8 @@ int sysfs_read_file(const char * path, char **output) goto free_out; } result[length] = '\0'; - if (result[length-1] == '\n') - result[length-1] = '\0'; + if ((n = strchr(result, '\n')) != NULL) + *n = '\0'; *output = result; ret = 0; goto out; diff --git a/src/version.h.in b/src/version.h.in deleted file mode 100644 index bcc0fda..0000000 --- a/src/version.h.in +++ /dev/null @@ -1 +0,0 @@ -#define BIOSDEVNAME_VERSION "@PACKAGE_VERSION@"