From 84c8d1bba90d5f9857b0724ebf6a35045ca3f30f Mon Sep 17 00:00:00 2001 From: Martin Mares Date: Sat, 27 Dec 2003 21:33:12 +0000 Subject: [PATCH] Preliminary support for PCI domains git-archimport-id: mj@ucw.cz--public/pciutils--main--2.2--patch-34 --- ChangeLog | 22 ++++++++++++++++++++++ TODO | 6 ++++-- lib/access.c | 4 +++- lib/dump.c | 2 +- lib/filter.c | 30 +++++++++++++++++++++++------- lib/generic.c | 8 +++++--- lib/internal.h | 2 +- lib/pci.h | 13 ++++++------- lib/proc.c | 1 - lib/sysfs.c | 16 ++++++++++++---- lspci.c | 34 ++++++++++++++++++++++++---------- setpci.c | 2 +- 12 files changed, 102 insertions(+), 38 deletions(-) diff --git a/ChangeLog b/ChangeLog index 1e51c6c..3b77271 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,5 +1,27 @@ 2003-12-27 Martin Mares + * lspci.c: Devices in domains different from 0 have their slot number + printed as "::.". + + * lib/filter.c: Slot filters understand domains. + + * lib/generic.c: Mention the domain in slot numbers in all error messages. + + * lib/internal.h: The #ifdef for Linux was wrong. + + * lib/access.c (pci_get_dev): Added support for domains. + + * lib/sysfs.c (sysfs_scan): Read vendor and device ID from the config + registers (or to be precise, leave it for the generic parts of the pcilib + to do so) instead of reading them from the sysfs. It's faster this way. + + * lspci.c (show_pcix): Don't touch pci_dev->hdrtype, it's an internal + variable. Better read it from the config registers (it's cached anyway). + + * lib/sysfs.c (sysfs_scan), lib/proc.c (proc_scan): Don't read the hdrtype. + lib/generic.c (pci_generic_fill_info): If hdrtype is -1 (unset), read it. + Saves lots of unnecessary file accesses. + * lib/pci.h (PCIADDR_PORT_FMT): Use %llx instead of %Lx, because the latter is not supported by all C libraries. diff --git a/TODO b/TODO index 86c2b09..9e39125 100644 --- a/TODO +++ b/TODO @@ -6,5 +6,7 @@ - names.c: rewrite - support for domains: - - pci_get_dev - - filters + - filters: doc and helps + - reading of dumps + - tree view + - map mode diff --git a/lib/access.c b/lib/access.c index 55060b5..eee22d2 100644 --- a/lib/access.c +++ b/lib/access.c @@ -194,6 +194,7 @@ pci_alloc_dev(struct pci_access *a) bzero(d, sizeof(*d)); d->access = a; d->methods = a->methods; + d->hdrtype = -1; if (d->methods->init_dev) d->methods->init_dev(d); return d; @@ -209,10 +210,11 @@ pci_link_dev(struct pci_access *a, struct pci_dev *d) } struct pci_dev * -pci_get_dev(struct pci_access *a, int bus, int dev, int func) +pci_get_dev(struct pci_access *a, int domain, int bus, int dev, int func) { struct pci_dev *d = pci_alloc_dev(a); + d->domain = domain; d->bus = bus; d->dev = dev; d->func = func; diff --git a/lib/dump.c b/lib/dump.c index 90293e4..d3b154f 100644 --- a/lib/dump.c +++ b/lib/dump.c @@ -44,7 +44,7 @@ dump_init(struct pci_access *a) if (len >= 8 && buf[2] == ':' && buf[5] == '.' && buf[7] == ' ' && sscanf(buf, "%x:%x.%d ", &bn, &dn, &fn) == 3) { - dev = pci_get_dev(a, bn, dn, fn); + dev = pci_get_dev(a, 0, bn, dn, fn); dev->aux = pci_malloc(a, 256); memset(dev->aux, 0xff, 256); pci_link_dev(a, dev); diff --git a/lib/filter.c b/lib/filter.c index 848eed2..e66a470 100644 --- a/lib/filter.c +++ b/lib/filter.c @@ -14,27 +14,42 @@ void pci_filter_init(struct pci_access *a UNUSED, struct pci_filter *f) { - f->bus = f->slot = f->func = -1; + f->domain = f->bus = f->slot = f->func = -1; f->vendor = f->device = -1; } -/* Slot filter syntax: [[bus]:][slot][.[func]] */ +/* Slot filter syntax: [[[domain]:][bus]:][slot][.[func]] */ char * pci_filter_parse_slot(struct pci_filter *f, char *str) { - char *colon = strchr(str, ':'); + char *colon = strrchr(str, ':'); char *dot = strchr((colon ? colon + 1 : str), '.'); char *mid = str; - char *e; + char *e, *bus, *colon2; if (colon) { *colon++ = 0; mid = colon; - if (str[0] && strcmp(str, "*")) + colon2 = strchr(str, ':'); + if (colon2) { - long int x = strtol(str, &e, 16); + *colon2++ = 0; + bus = colon2; + if (str[0] && strcmp(str, "*")) + { + long int x = strtol(bus, &e, 16); + if ((e && *e) || (x < 0 || x > 0xffff)) + return "Invalid domain number"; + f->domain = x; + } + } + else + bus = str; + if (bus[0] && strcmp(bus, "*")) + { + long int x = strtol(bus, &e, 16); if ((e && *e) || (x < 0 || x > 0xff)) return "Invalid bus number"; f->bus = x; @@ -92,7 +107,8 @@ pci_filter_parse_id(struct pci_filter *f, char *str) int pci_filter_match(struct pci_filter *f, struct pci_dev *d) { - if ((f->bus >= 0 && f->bus != d->bus) || + if ((f->domain >= 0 && f->domain != d->domain) || + (f->bus >= 0 && f->bus != d->bus) || (f->slot >= 0 && f->slot != d->dev) || (f->func >= 0 && f->func != d->func)) return 0; diff --git a/lib/generic.c b/lib/generic.c index d4f2600..25d3faa 100644 --- a/lib/generic.c +++ b/lib/generic.c @@ -58,7 +58,7 @@ pci_generic_scan_bus(struct pci_access *a, byte *busmap, int bus) pci_generic_scan_bus(a, busmap, pci_read_byte(t, PCI_SECONDARY_BUS)); break; default: - a->debug("Device %02x:%02x.%d has unknown header type %02x.\n", d->bus, d->dev, d->func, ht); + a->debug("Device %04x:%02x:%02x.%d has unknown header type %02x.\n", d->domain, d->bus, d->dev, d->func, ht); } } } @@ -79,6 +79,8 @@ pci_generic_fill_info(struct pci_dev *d, int flags) { struct pci_access *a = d->access; + if ((flags & (PCI_FILL_BASES | PCI_FILL_ROM_BASE)) && d->hdrtype < 0) + d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE); if (flags & PCI_FILL_IDENT) { d->vendor_id = pci_read_word(d, PCI_VENDOR_ID); @@ -121,7 +123,7 @@ pci_generic_fill_info(struct pci_dev *d, int flags) if ((x & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64) { if (i >= cnt-1) - a->warning("%02x:%02x.%d: Invalid 64-bit address seen.", d->bus, d->dev, d->func); + a->warning("%04x:%02x:%02x.%d: Invalid 64-bit address seen.", d->domain, d->bus, d->dev, d->func); else { u32 y = pci_read_long(d, PCI_BASE_ADDRESS_0 + (++i)*4); @@ -130,7 +132,7 @@ pci_generic_fill_info(struct pci_dev *d, int flags) #else if (y) { - a->warning("%02x:%02x.%d 64-bit device address ignored.", d->bus, d->dev, d->func); + a->warning("%04x:%02x:%02x.%d 64-bit device address ignored.", d->domain, d->bus, d->dev, d->func); d->base_addr[i-1] = 0; } #endif diff --git a/lib/internal.h b/lib/internal.h index b18ccd1..41ad612 100644 --- a/lib/internal.h +++ b/lib/internal.h @@ -15,7 +15,7 @@ #define inline #endif -#ifdef HAVE_PM_LINUX_BYTEORDER_H +#ifdef HAVE_LINUX_BYTEORDER_H #include #define cpu_to_le16 __cpu_to_le16 diff --git a/lib/pci.h b/lib/pci.h index 50c2961..b031f53 100644 --- a/lib/pci.h +++ b/lib/pci.h @@ -106,7 +106,7 @@ void pci_cleanup(struct pci_access *); /* Scanning of devices */ void pci_scan_bus(struct pci_access *acc); -struct pci_dev *pci_get_dev(struct pci_access *acc, int bus, int dev, int func); /* Raw access to specified device */ +struct pci_dev *pci_get_dev(struct pci_access *acc, int domain, int bus, int dev, int func); /* Raw access to specified device */ void pci_free_dev(struct pci_dev *); /* @@ -115,9 +115,8 @@ void pci_free_dev(struct pci_dev *); struct pci_dev { struct pci_dev *next; /* Next device in the chain */ - word domain; /* PCI domain (host bridge) */ - byte bus; /* Bus inside domain */ - byte dev, func; /* Device and function */ + u16 domain; /* PCI domain (host bridge) */ + byte bus, dev, func; /* Bus inside domain, device and function */ /* These fields are set by pci_fill_info() */ int known_fields; /* Set of info fields already known */ @@ -131,9 +130,9 @@ struct pci_dev { /* Fields used internally: */ struct pci_access *access; struct pci_methods *methods; - byte *cache; /* Cached information */ + byte *cache; /* Cached config registers */ int cache_len; - int hdrtype; /* Direct methods: header type */ + int hdrtype; /* Cached header type, -1 if unknown */ void *aux; /* Auxillary data */ }; @@ -165,7 +164,7 @@ void pci_setup_cache(struct pci_dev *, byte *cache, int len); */ struct pci_filter { - int bus, slot, func; /* -1 = ANY */ + int domain, bus, slot, func; /* -1 = ANY */ int vendor, device; }; diff --git a/lib/proc.c b/lib/proc.c index 8afe7a3..0262143 100644 --- a/lib/proc.c +++ b/lib/proc.c @@ -97,7 +97,6 @@ proc_scan(struct pci_access *a) d->func = PCI_FUNC(dfn & 0xff); d->vendor_id = vend >> 16U; d->device_id = vend & 0xffff; - d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f; known = PCI_FILL_IDENT; if (!a->buscentric) { diff --git a/lib/sysfs.c b/lib/sysfs.c index 70511b1..c0cf5a3 100644 --- a/lib/sysfs.c +++ b/lib/sysfs.c @@ -39,7 +39,7 @@ sysfs_detect(struct pci_access *a) { if (access(sysfs_name(a), R_OK)) { - a->debug("Cannot open %s", sysfs_name(a)); + a->debug("...cannot open %s", sysfs_name(a)); return 0; } a->debug("...using %s", sysfs_name(a)); @@ -165,14 +165,22 @@ static void sysfs_scan(struct pci_access *a) d->bus = bus; d->dev = dev; d->func = func; - d->hdrtype = pci_read_byte(d, PCI_HEADER_TYPE) & 0x7f; if (!a->buscentric) { sysfs_get_resources(d); + d->irq = sysfs_get_value(d, "irq"); + d->known_fields = PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES; +#if 0 + /* + * We prefer reading these from the config registers, it's faster. + * However, it would be possible and maybe even useful to hack the kernel + * to believe that some device has a different ID. If you do it, just + * enable this piece of code. --mj + */ d->vendor_id = sysfs_get_value(d, "vendor"); d->device_id = sysfs_get_value(d, "device"); - d->irq = sysfs_get_value(d, "irq"); - d->known_fields = PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES; + d->known_fields |= PCI_FILL_IDENT; +#endif } pci_link_dev(a, d); } diff --git a/lspci.c b/lspci.c index 242f497..2368ceb 100644 --- a/lspci.c +++ b/lspci.c @@ -34,7 +34,7 @@ Usage: lspci []\n\ -b\t\tBus-centric view (PCI addresses and IRQ's instead of those seen by the CPU)\n\ -x\t\tShow hex-dump of the standard portion of config space\n\ -xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n\ --s [[]:][][.[]]\tShow only devices in selected slots\n\ +-s [[[[]:]]:][][.[]]\tShow only devices in selected slots\n\ -d []:[]\tShow only selected devices\n\ -t\t\tShow bus tree\n\ -m\t\tProduce machine-readable output\n\ @@ -160,6 +160,10 @@ compare_them(const void *A, const void *B) const struct pci_dev *a = (*(const struct device **)A)->dev; const struct pci_dev *b = (*(const struct device **)B)->dev; + if (a->domain < b->domain) + return -1; + if (a->domain > b->domain) + return 1; if (a->bus < b->bus) return -1; if (a->bus > b->bus) @@ -204,6 +208,16 @@ sort_them(void) #define FLAG(x,y) ((x & y) ? '+' : '-') +static void +show_slot_name(struct device *d) +{ + struct pci_dev *p = d->dev; + + if (p->domain) + printf("%04x:", p->domain); + printf("%02x:%02x.%d", p->bus, p->dev, p->func); +} + static void show_terse(struct device *d) { @@ -211,10 +225,8 @@ show_terse(struct device *d) struct pci_dev *p = d->dev; byte classbuf[128], devbuf[128]; - printf("%02x:%02x.%x %s: %s", - p->bus, - p->dev, - p->func, + show_slot_name(d); + printf(" %s: %s", pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, get_conf_word(d, PCI_CLASS_DEVICE), 0, 0, 0), @@ -531,7 +543,7 @@ show_pcix_bridge(struct device *d, int where) static void show_pcix(struct device *d, int where) { - switch (d->dev->hdrtype) + switch (get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f) { case PCI_HEADER_TYPE_NORMAL: show_pcix_nobridge(d, where); @@ -996,7 +1008,9 @@ show_machine(struct device *d) if (verbose) { - printf("Device:\t%02x:%02x.%x\n", p->bus, p->dev, p->func); + printf("Device:\t"); + show_slot_name(d); + putchar('\n'); printf("Class:\t%s\n", pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, get_conf_word(d, PCI_CLASS_DEVICE), 0, 0, 0)); printf("Vendor:\t%s\n", @@ -1017,8 +1031,8 @@ show_machine(struct device *d) } else { - printf("%02x:%02x.%x ", p->bus, p->dev, p->func); - printf("\"%s\" \"%s\" \"%s\"", + show_slot_name(d); + printf(" \"%s\" \"%s\" \"%s\"", pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, get_conf_word(d, PCI_CLASS_DEVICE), 0, 0, 0), pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, @@ -1362,7 +1376,7 @@ do_map_bus(int bus) for(func = 0; func < func_limit; func++) if (filter.func < 0 || filter.func == func) { - struct pci_dev *p = pci_get_dev(pacc, bus, dev, func); + struct pci_dev *p = pci_get_dev(pacc, 0, bus, dev, func); u16 vendor = pci_read_word(p, PCI_VENDOR_ID); if (vendor && vendor != 0xffff) { diff --git a/setpci.c b/setpci.c index ce32473..9c78176 100644 --- a/setpci.c +++ b/setpci.c @@ -261,7 +261,7 @@ usage(char *msg, ...) -v\t\tBe verbose\n\ -D\t\tList changes, don't commit them\n" GENERIC_HELP -":\t-s [[]:][][.[]]\n" +":\t-s [[[]:][]:][][.[]]\n" "\t|\t-d []:[]\n" ":\t\t[.(B|W|L)]\n" " |\t\t\n" -- 2.39.2