From: Pali Rohár Date: Sat, 20 Nov 2021 13:36:40 +0000 (+0100) Subject: libpci: Add support for filling bridge resources X-Git-Tag: v3.8.0~43 X-Git-Url: http://mj.ucw.cz/gitweb/?a=commitdiff_plain;h=119c1376f9ca4d359a1816af9d31f4a2c2c83307;p=pciutils.git libpci: Add support for filling bridge resources Extend libpci API and ABI to fill bridge resources from sysfs. --- diff --git a/lib/access.c b/lib/access.c index 9bd6989..b8fdbe2 100644 --- a/lib/access.c +++ b/lib/access.c @@ -189,7 +189,7 @@ pci_reset_properties(struct pci_dev *d) } int -pci_fill_info_v35(struct pci_dev *d, int flags) +pci_fill_info_v38(struct pci_dev *d, int flags) { unsigned int uflags = flags; if (uflags & PCI_FILL_RESCAN) @@ -203,19 +203,21 @@ pci_fill_info_v35(struct pci_dev *d, int flags) } /* In version 3.1, pci_fill_info got new flags => versioned alias */ -/* In versions 3.2, 3.3, 3.4 and 3.5, the same has happened */ -STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v35(d, flags)); -DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v35); -DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v35); -DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v35); -DEFINE_ALIAS(int pci_fill_info_v33(struct pci_dev *d, int flags), pci_fill_info_v35); -DEFINE_ALIAS(int pci_fill_info_v34(struct pci_dev *d, int flags), pci_fill_info_v35); +/* In versions 3.2, 3.3, 3.4, 3.5 and 3.8, the same has happened */ +STATIC_ALIAS(int pci_fill_info(struct pci_dev *d, int flags), pci_fill_info_v38(d, flags)); +DEFINE_ALIAS(int pci_fill_info_v30(struct pci_dev *d, int flags), pci_fill_info_v38); +DEFINE_ALIAS(int pci_fill_info_v31(struct pci_dev *d, int flags), pci_fill_info_v38); +DEFINE_ALIAS(int pci_fill_info_v32(struct pci_dev *d, int flags), pci_fill_info_v38); +DEFINE_ALIAS(int pci_fill_info_v33(struct pci_dev *d, int flags), pci_fill_info_v38); +DEFINE_ALIAS(int pci_fill_info_v34(struct pci_dev *d, int flags), pci_fill_info_v38); +DEFINE_ALIAS(int pci_fill_info_v35(struct pci_dev *d, int flags), pci_fill_info_v38); SYMBOL_VERSION(pci_fill_info_v30, pci_fill_info@LIBPCI_3.0); SYMBOL_VERSION(pci_fill_info_v31, pci_fill_info@LIBPCI_3.1); SYMBOL_VERSION(pci_fill_info_v32, pci_fill_info@LIBPCI_3.2); SYMBOL_VERSION(pci_fill_info_v33, pci_fill_info@LIBPCI_3.3); SYMBOL_VERSION(pci_fill_info_v34, pci_fill_info@LIBPCI_3.4); -SYMBOL_VERSION(pci_fill_info_v35, pci_fill_info@@LIBPCI_3.5); +SYMBOL_VERSION(pci_fill_info_v35, pci_fill_info@LIBPCI_3.5); +SYMBOL_VERSION(pci_fill_info_v38, pci_fill_info@@LIBPCI_3.8); void pci_setup_cache(struct pci_dev *d, byte *cache, int len) diff --git a/lib/caps.c b/lib/caps.c index 3c025a9..039c86f 100644 --- a/lib/caps.c +++ b/lib/caps.c @@ -128,7 +128,7 @@ pci_find_cap_nr(struct pci_dev *d, unsigned int id, unsigned int type, unsigned int target = (cap_number ? *cap_number : 0); unsigned int index = 0; - pci_fill_info_v35(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS)); + pci_fill_info_v38(d, ((type == PCI_CAP_NORMAL) ? PCI_FILL_CAPS : PCI_FILL_EXT_CAPS)); for (c=d->first_cap; c; c=c->next) { diff --git a/lib/filter.c b/lib/filter.c index 573fb28..195f813 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -129,7 +129,7 @@ pci_filter_match_v33(struct pci_filter *f, struct pci_dev *d) return 0; if (f->device >= 0 || f->vendor >= 0) { - pci_fill_info_v35(d, PCI_FILL_IDENT); + pci_fill_info_v38(d, PCI_FILL_IDENT); if ((f->device >= 0 && f->device != d->device_id) || (f->vendor >= 0 && f->vendor != d->vendor_id)) return 0; diff --git a/lib/internal.h b/lib/internal.h index 942e3cb..a1c8cc8 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -74,6 +74,7 @@ int pci_fill_info_v32(struct pci_dev *, int flags) VERSIONED_ABI; int pci_fill_info_v33(struct pci_dev *, int flags) VERSIONED_ABI; int pci_fill_info_v34(struct pci_dev *, int flags) VERSIONED_ABI; int pci_fill_info_v35(struct pci_dev *, int flags) VERSIONED_ABI; +int pci_fill_info_v38(struct pci_dev *, int flags) VERSIONED_ABI; static inline int want_fill(struct pci_dev *d, unsigned want_fields, unsigned int try_fields) { @@ -87,6 +88,11 @@ static inline int want_fill(struct pci_dev *d, unsigned want_fields, unsigned in } } +static inline void clear_fill(struct pci_dev *d, unsigned clear_fields) +{ + d->known_fields &= ~clear_fields; +} + struct pci_property { struct pci_property *next; u32 key; diff --git a/lib/libpci.ver b/lib/libpci.ver index e20c3f5..73f7fa7 100644 --- a/lib/libpci.ver +++ b/lib/libpci.ver @@ -82,3 +82,8 @@ LIBPCI_3.7 { global: pci_find_cap_nr; }; + +LIBPCI_3.8 { + global: + pci_fill_info; +}; diff --git a/lib/pci.h b/lib/pci.h index 328a468..b9fd9bf 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -142,6 +142,9 @@ struct pci_dev { pciaddr_t flags[6]; /* PCI_IORESOURCE_* flags for regions */ pciaddr_t rom_flags; /* PCI_IORESOURCE_* flags for expansion ROM */ int domain; /* PCI domain (host bridge) */ + pciaddr_t bridge_base_addr[4]; /* Bridge base addresses (without flags) */ + pciaddr_t bridge_size[4]; /* Bridge sizes */ + pciaddr_t bridge_flags[4]; /* PCI_IORESOURCE_* flags for bridge addresses */ /* Fields used internally */ struct pci_access *access; @@ -205,6 +208,7 @@ char *pci_get_string_property(struct pci_dev *d, u32 prop) PCI_ABI; #define PCI_FILL_IO_FLAGS 0x1000 #define PCI_FILL_DT_NODE 0x2000 /* Device tree node */ #define PCI_FILL_IOMMU_GROUP 0x4000 +#define PCI_FILL_BRIDGE_BASES 0x8000 #define PCI_FILL_RESCAN 0x00010000 void pci_setup_cache(struct pci_dev *, u8 *cache, int len) PCI_ABI; diff --git a/lib/sysfs.c b/lib/sysfs.c index 4b8b2cd..fe3f0e5 100644 --- a/lib/sysfs.c +++ b/lib/sysfs.c @@ -153,14 +153,17 @@ sysfs_get_resources(struct pci_dev *d) { struct pci_access *a = d->access; char namebuf[OBJNAMELEN], buf[256]; + struct { pciaddr_t flags, base_addr, size; } lines[10]; + int have_bar_bases, have_rom_base, have_bridge_bases; FILE *file; int i; + have_bar_bases = have_rom_base = have_bridge_bases = 0; sysfs_obj_name(d, "resource", namebuf); file = fopen(namebuf, "r"); if (!file) a->error("Cannot open %s: %s", namebuf, strerror(errno)); - for (i = 0; i < 7; i++) + for (i = 0; i < 7+6+4+1; i++) { unsigned long long start, end, size, flags; if (!fgets(buf, sizeof(buf), file)) @@ -177,16 +180,55 @@ sysfs_get_resources(struct pci_dev *d) flags &= PCI_ADDR_FLAG_MASK; d->base_addr[i] = start | flags; d->size[i] = size; + have_bar_bases = 1; } - else + else if (i == 6) { d->rom_flags = flags; flags &= PCI_ADDR_FLAG_MASK; d->rom_base_addr = start | flags; d->rom_size = size; + have_rom_base = 1; } + else if (i < 7+6+4) + { + /* + * If kernel was compiled without CONFIG_PCI_IOV option then after + * the ROM line for configured bridge device (that which had set + * subordinary bus number to non-zero value) are four additional lines + * which describe resources behind bridge. For PCI-to-PCI bridges they + * are: IO, MEM, PREFMEM and empty. For CardBus bridges they are: IO0, + * IO1, MEM0 and MEM1. For unconfigured bridges and other devices + * there is no additional line after the ROM line. If kernel was + * compiled with CONFIG_PCI_IOV option then after the ROM line and + * before the first bridge resource line are six additional lines + * which describe IOV resources. Read all remaining lines in resource + * file and based on the number of remaining lines (0, 4, 6, 10) parse + * resources behind bridge. + */ + lines[i-7].flags = flags; + lines[i-7].base_addr = start; + lines[i-7].size = size; + } + } + if (i == 7+4 || i == 7+6+4) + { + int offset = (i == 7+6+4) ? 6 : 0; + for (i = 0; i < 4; i++) + { + d->bridge_flags[i] = lines[offset+i].flags; + d->bridge_base_addr[i] = lines[offset+i].base_addr; + d->bridge_size[i] = lines[offset+i].size; + } + have_bridge_bases = 1; } fclose(file); + if (!have_bar_bases) + clear_fill(d, PCI_FILL_BASES | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS); + if (!have_rom_base) + clear_fill(d, PCI_FILL_ROM_BASE); + if (!have_bridge_bases) + clear_fill(d, PCI_FILL_BRIDGE_BASES); } static void sysfs_scan(struct pci_access *a) @@ -307,7 +349,7 @@ sysfs_fill_info(struct pci_dev *d, unsigned int flags) d->device_class = sysfs_get_value(d, "class", 1) >> 8; if (want_fill(d, flags, PCI_FILL_IRQ)) d->irq = sysfs_get_value(d, "irq", 1); - if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS)) + if (want_fill(d, flags, PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_IO_FLAGS | PCI_FILL_BRIDGE_BASES)) sysfs_get_resources(d); }