X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lspci.c;h=af94eeb0aa2bb2b5c042142597204f9ef3a99811;hb=b569ef09d76169e6cdac8934885fa3862c48a2ac;hp=242f497e0795f900fa903a05b0f84153b180a5a2;hpb=4284af587a271584985bc69e7511fa75ea3d7d3d;p=pciutils.git diff --git a/lspci.c b/lspci.c index 242f497..af94eeb 100644 --- a/lspci.c +++ b/lspci.c @@ -1,7 +1,7 @@ /* * The PCI Utilities -- List All PCI Devices * - * Copyright (c) 1997--2003 Martin Mares + * Copyright (c) 1997--2004 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -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), @@ -392,8 +404,7 @@ format_agp_rate(int rate, char *buf, int agp3) { if (c != buf) *c++ = ','; - *c++ = 'x'; - *c++ = '0' + (1 << (i + 2*agp3)); + c += sprintf(c, "x%d", 1 << (i + 2*agp3)); } if (c != buf) *c = 0; @@ -405,7 +416,7 @@ static void show_agp(struct device *d, int where, int cap) { u32 t; - char rate[8]; + char rate[16]; int ver, rev; int agp3 = 0; @@ -531,7 +542,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); @@ -542,6 +553,322 @@ show_pcix(struct device *d, int where) } } +static inline char * +ht_link_width(unsigned width) +{ + static char * const widths[8] = { "8bit", "16bit", "[2]", "32bit", "2bit", "4bit", "[6]", "N/C" }; + return widths[width]; +} + +static inline char * +ht_link_freq(unsigned freq) +{ + static char * const freqs[16] = { "200MHz", "300MHz", "400MHz", "500MHz", "600MHz", "800MHz", "1.0GHz", "1.2GHz", + "1.4GHz", "1.6GHz", "[a]", "[b]", "[c]", "[d]", "[e]", "Vend" }; + return freqs[freq]; +} + +static void +show_ht_pri(struct device *d, int where, int cmd) +{ + u16 lctr0, lcnf0, lctr1, lcnf1, eh; + u8 rid, lfrer0, lfcap0, ftr, lfrer1, lfcap1, mbu, mlu, bn; + + printf("HyperTransport: Slave or Primary Interface\n"); + if (verbose < 2) + return; + + printf("\t\tCommand: BaseUnitID=%u UnitCnt=%u MastHost%c DefDir%c DUL%c\n", + (cmd & PCI_HT_PRI_CMD_BUID), + (cmd & PCI_HT_PRI_CMD_UC) >> 5, + FLAG(cmd, PCI_HT_PRI_CMD_MH), + FLAG(cmd, PCI_HT_PRI_CMD_DD), + FLAG(cmd, PCI_HT_PRI_CMD_DUL)); + config_fetch(d, where + PCI_HT_PRI_LCTR0, PCI_HT_PRI_SIZEOF - PCI_HT_PRI_LCTR0); + lctr0 = get_conf_word(d, where + PCI_HT_PRI_LCTR0); + printf("\t\tLink Control 0: CFlE%c CST%c CFE%c > 8, + FLAG(lctr0, PCI_HT_LCTR_ISOCEN), + FLAG(lctr0, PCI_HT_LCTR_LSEN), + FLAG(lctr0, PCI_HT_LCTR_EXTCTL), + FLAG(lctr0, PCI_HT_LCTR_64B)); + lcnf0 = get_conf_word(d, where + PCI_HT_PRI_LCNF0); + printf("\t\tLink Config 0: MLWI=%s DwFcIn%c MLWO=%s DwFcOut%c LWI=%s DwFcInEn%c LWO=%s DwFcOutEn%c\n", + ht_link_width(lcnf0 & PCI_HT_LCNF_MLWI), + FLAG(lcnf0, PCI_HT_LCNF_DFI), + ht_link_width((lcnf0 & PCI_HT_LCNF_MLWO) >> 4), + FLAG(lcnf0, PCI_HT_LCNF_DFO), + ht_link_width((lcnf0 & PCI_HT_LCNF_LWI) >> 8), + FLAG(lcnf0, PCI_HT_LCNF_DFIE), + ht_link_width((lcnf0 & PCI_HT_LCNF_LWO) >> 12), + FLAG(lcnf0, PCI_HT_LCNF_DFOE)); + lctr1 = get_conf_word(d, where + PCI_HT_PRI_LCTR1); + printf("\t\tLink Control 1: CFlE%c CST%c CFE%c > 8, + FLAG(lctr1, PCI_HT_LCTR_ISOCEN), + FLAG(lctr1, PCI_HT_LCTR_LSEN), + FLAG(lctr1, PCI_HT_LCTR_EXTCTL), + FLAG(lctr1, PCI_HT_LCTR_64B)); + lcnf1 = get_conf_word(d, where + PCI_HT_PRI_LCNF1); + printf("\t\tLink Config 1: MLWI=%s DwFcIn%c MLWO=%s DwFcOut%c LWI=%s DwFcInEn%c LWO=%s DwFcOutEn%c\n", + ht_link_width(lcnf1 & PCI_HT_LCNF_MLWI), + FLAG(lcnf1, PCI_HT_LCNF_DFI), + ht_link_width((lcnf1 & PCI_HT_LCNF_MLWO) >> 4), + FLAG(lcnf1, PCI_HT_LCNF_DFO), + ht_link_width((lcnf1 & PCI_HT_LCNF_LWI) >> 8), + FLAG(lcnf1, PCI_HT_LCNF_DFIE), + ht_link_width((lcnf1 & PCI_HT_LCNF_LWO) >> 12), + FLAG(lcnf1, PCI_HT_LCNF_DFOE)); + rid = get_conf_byte(d, where + PCI_HT_PRI_RID); + printf("\t\tRevision ID: %u.%02u\n", + (rid & PCI_HT_RID_MAJ) >> 5, (rid & PCI_HT_RID_MIN)); + lfrer0 = get_conf_byte(d, where + PCI_HT_PRI_LFRER0); + printf("\t\tLink Frequency 0: %s\n", ht_link_freq(lfrer0 & PCI_HT_LFRER_FREQ)); + printf("\t\tLink Error 0: > 2, + FLAG(cmd, PCI_HT_SEC_CMD_CS), + FLAG(cmd, PCI_HT_SEC_CMD_HH), + FLAG(cmd, PCI_HT_SEC_CMD_AS), + FLAG(cmd, PCI_HT_SEC_CMD_HIECE), + FLAG(cmd, PCI_HT_SEC_CMD_DUL)); + config_fetch(d, where + PCI_HT_SEC_LCTR, PCI_HT_SEC_SIZEOF - PCI_HT_SEC_LCTR); + lctr = get_conf_word(d, where + PCI_HT_SEC_LCTR); + printf("\t\tLink Control: CFlE%c CST%c CFE%c > 8, + FLAG(lctr, PCI_HT_LCTR_ISOCEN), + FLAG(lctr, PCI_HT_LCTR_LSEN), + FLAG(lctr, PCI_HT_LCTR_EXTCTL), + FLAG(lctr, PCI_HT_LCTR_64B)); + lcnf = get_conf_word(d, where + PCI_HT_SEC_LCNF); + printf("\t\tLink Config: MLWI=%s DwFcIn%c MLWO=%s DwFcOut%c LWI=%s DwFcInEn%c LWO=%s DwFcOutEn%c\n", + ht_link_width(lcnf & PCI_HT_LCNF_MLWI), + FLAG(lcnf, PCI_HT_LCNF_DFI), + ht_link_width((lcnf & PCI_HT_LCNF_MLWO) >> 4), + FLAG(lcnf, PCI_HT_LCNF_DFO), + ht_link_width((lcnf & PCI_HT_LCNF_LWI) >> 8), + FLAG(lcnf, PCI_HT_LCNF_DFIE), + ht_link_width((lcnf & PCI_HT_LCNF_LWO) >> 12), + FLAG(lcnf, PCI_HT_LCNF_DFOE)); + rid = get_conf_byte(d, where + PCI_HT_SEC_RID); + printf("\t\tRevision ID: %u.%02u\n", + (rid & PCI_HT_RID_MAJ) >> 5, (rid & PCI_HT_RID_MIN)); + lfrer = get_conf_byte(d, where + PCI_HT_SEC_LFRER); + printf("\t\tLink Frequency: %s\n", ht_link_freq(lfrer & PCI_HT_LFRER_FREQ)); + printf("\t\tLink Error: > 5, (cmd & PCI_HT_RID_MIN)); + break; + case PCI_HT_CMD_TYP_UIDC: + printf("HyperTransport: UnitID Clumping\n"); + break; + case PCI_HT_CMD_TYP_ECSA: + printf("HyperTransport: Extended Configuration Space Access\n"); + break; + case PCI_HT_CMD_TYP_AM: + printf("HyperTransport: Address Mapping\n"); + break; + case PCI_HT_CMD_TYP_MSIM: + printf("HyperTransport: MSI Mapping\n"); + break; + case PCI_HT_CMD_TYP_DR: + printf("HyperTransport: DirectRoute\n"); + break; + case PCI_HT_CMD_TYP_VCS: + printf("HyperTransport: VCSet\n"); + break; + case PCI_HT_CMD_TYP_RM: + printf("HyperTransport: Retry Mode\n"); + break; + case PCI_HT_CMD_TYP_X86: + printf("HyperTransport: X86 (reserved)\n"); + break; + default: + printf("HyperTransport: #%02x\n", type >> 11); + } +} + static void show_rom(struct device *d) { @@ -648,6 +975,9 @@ show_caps(struct device *d) case PCI_CAP_ID_PCIX: show_pcix(d, where); break; + case PCI_CAP_ID_HT: + show_ht(d, where, cap); + break; default: printf("#%02x [%04x]\n", id, cap); } @@ -676,6 +1006,7 @@ show_htype1(struct device *d) u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE); u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT); u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK; + word sec_stat = get_conf_word(d, PCI_SEC_STATUS); word brc = get_conf_word(d, PCI_BRIDGE_CONTROL); int verb = verbose > 2; @@ -733,8 +1064,19 @@ show_htype1(struct device *d) } } - if (get_conf_word(d, PCI_SEC_STATUS) & PCI_STATUS_SIG_SYSTEM_ERROR) - printf("\tSecondary status: SERR\n"); + if (verbose > 1) + printf("\tSecondary status: 66Mhz%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c 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 +1361,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, @@ -1069,35 +1413,38 @@ struct bridge { struct bridge *chain; /* Single-linked list of bridges */ struct bridge *next, *child; /* Tree of bridges */ struct bus *first_bus; /* List of busses connected to this bridge */ + unsigned int domain; unsigned int primary, secondary, subordinate; /* Bus numbers */ struct device *br_dev; }; struct bus { + unsigned int domain; unsigned int number; struct bus *sibling; struct device *first_dev, **last_dev; }; -static struct bridge host_bridge = { NULL, NULL, NULL, NULL, ~0, 0, ~0, NULL }; +static struct bridge host_bridge = { NULL, NULL, NULL, NULL, 0, ~0, 0, ~0, NULL }; static struct bus * -find_bus(struct bridge *b, unsigned int n) +find_bus(struct bridge *b, unsigned int domain, unsigned int n) { struct bus *bus; for(bus=b->first_bus; bus; bus=bus->sibling) - if (bus->number == n) + if (bus->domain == domain && bus->number == n) break; return bus; } static struct bus * -new_bus(struct bridge *b, unsigned int n) +new_bus(struct bridge *b, unsigned int domain, unsigned int n) { struct bus *bus = xmalloc(sizeof(struct bus)); bus = xmalloc(sizeof(struct bus)); + bus->domain = domain; bus->number = n; bus->sibling = b->first_bus; bus->first_dev = NULL; @@ -1112,19 +1459,19 @@ insert_dev(struct device *d, struct bridge *b) struct pci_dev *p = d->dev; struct bus *bus; - if (! (bus = find_bus(b, p->bus))) + if (! (bus = find_bus(b, p->domain, p->bus))) { struct bridge *c; for(c=b->child; c; c=c->next) - if (c->secondary <= p->bus && p->bus <= c->subordinate) + if (c->domain == p->domain && c->secondary <= p->bus && p->bus <= c->subordinate) { insert_dev(d, c); return; } - bus = new_bus(b, p->bus); + bus = new_bus(b, p->domain, p->bus); } /* Simple insertion at the end _does_ guarantee the correct order as the - * original device list was sorted by (bus, devfn) lexicographically + * original device list was sorted by (domain, bus, devfn) lexicographically * and all devices on the new list have the same bus number. */ *bus->last_dev = d; @@ -1149,6 +1496,7 @@ grow_tree(void) (ht == PCI_HEADER_TYPE_BRIDGE || ht == PCI_HEADER_TYPE_CARDBUS)) { b = xmalloc(sizeof(struct bridge)); + b->domain = d->dev->domain; if (ht == PCI_HEADER_TYPE_BRIDGE) { b->primary = get_conf_byte(d, PCI_CB_PRIMARY_BUS); @@ -1177,7 +1525,8 @@ grow_tree(void) struct bridge *c, *best; best = NULL; for(c=&host_bridge; c; c=c->chain) - if (c != b && b->primary >= c->secondary && b->primary <= c->subordinate && + if (c != b && (c == &host_bridge || b->domain == c->domain) && + b->primary >= c->secondary && b->primary <= c->subordinate && (!best || best->subordinate - best->primary > c->subordinate - c->primary)) best = c; if (best) @@ -1190,8 +1539,8 @@ grow_tree(void) /* Insert secondary bus for each bridge */ for(b=&host_bridge; b; b=b->chain) - if (!find_bus(b, b->secondary)) - new_bus(b, b->secondary); + if (!find_bus(b, b->domain, b->secondary)) + new_bus(b, b->domain, b->secondary); /* Create bus structs and link devices */ @@ -1230,9 +1579,9 @@ show_tree_dev(struct device *d, byte *line, byte *p) if (b->br_dev == d) { if (b->secondary == b->subordinate) - p += sprintf(p, "-[%02x]-", b->secondary); + p += sprintf(p, "-[%04x:%02x]-", b->domain, b->secondary); else - p += sprintf(p, "-[%02x-%02x]-", b->secondary, b->subordinate); + p += sprintf(p, "-[%04x:%02x-%02x]-", b->domain, b->secondary, b->subordinate); show_tree_bridge(b, line, p); return; } @@ -1278,7 +1627,7 @@ show_tree_bridge(struct bridge *b, byte *line, byte *p) if (!b->first_bus->sibling) { if (b == &host_bridge) - p += sprintf(p, "[%02x]-", b->first_bus->number); + p += sprintf(p, "[%04x:%02x]-", b->domain, b->first_bus->number); show_tree_bus(b->first_bus, line, p); } else @@ -1288,11 +1637,11 @@ show_tree_bridge(struct bridge *b, byte *line, byte *p) while (u->sibling) { - k = p + sprintf(p, "+-[%02x]-", u->number); + k = p + sprintf(p, "+-[%04x:%02x]-", u->domain, u->number); show_tree_bus(u, line, k); u = u->sibling; } - k = p + sprintf(p, "\\-[%02x]-", u->number); + k = p + sprintf(p, "\\-[%04x:%02x]-", u->domain, u->number); show_tree_bus(u, line, k); } } @@ -1362,7 +1711,8 @@ 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); + /* XXX: Bus mapping supports only domain 0 */ + 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) {