X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lspci.c;h=aa6b37a8c1c42ceb47c14fcb72f536f090b94fec;hb=80e6c636fb1c5381f4ce95963ace48dc477c7599;hp=07e91844bcd64b3410ed4dcb8bc77d9ca4c49ee2;hpb=098174370094ba8c31f86bd9faed3796dcaeb1db;p=pciutils.git diff --git a/lspci.c b/lspci.c index 07e9184..aa6b37a 100644 --- a/lspci.c +++ b/lspci.c @@ -63,12 +63,31 @@ static struct pci_access *pacc; struct device { struct device *next; struct pci_dev *dev; - unsigned int config_cnt; - byte config[256]; + unsigned int config_cnt, config_bufsize; + byte *config; }; static struct device *first_dev; +static int +config_fetch(struct device *d, unsigned int pos, unsigned int len) +{ + unsigned int end = pos+len; + int result; + if (end <= d->config_cnt) + return 1; + if (end > d->config_bufsize) + { + while (end > d->config_bufsize) + d->config_bufsize *= 2; + d->config = xrealloc(d->config, d->config_bufsize); + } + result = pci_read_block(d->dev, pos, d->config + pos, len); + if (result && pos == d->config_cnt) + d->config_cnt = end; + return result; +} + static struct device * scan_device(struct pci_dev *p) { @@ -79,15 +98,16 @@ scan_device(struct pci_dev *p) d = xmalloc(sizeof(struct device)); bzero(d, sizeof(*d)); d->dev = p; - d->config_cnt = 64; + d->config_cnt = d->config_bufsize = 64; + d->config = xmalloc(64); if (!pci_read_block(p, 0, d->config, 64)) die("Unable to read the configuration space header."); if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS) { - /* For cardbus bridges, we need to fetch 64 bytes more to get the full standard header... */ - if (!pci_read_block(p, 64, d->config+64, 64)) + /* For cardbus bridges, we need to fetch 64 bytes more to get the + * full standard header... */ + if (!config_fetch(d, 64, 64)) die("Unable to read cardbus bridge extension data."); - d->config_cnt = 128; } pci_setup_cache(p, d->config, d->config_cnt); pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES); @@ -109,14 +129,6 @@ scan_devices(void) } } -static int -config_fetch(struct device *d, unsigned int pos, unsigned int len) -{ - if (pos + len < d->config_cnt) - return 1; - return pci_read_block(d->dev, pos, d->config + pos, len); -} - /* Config space accesses */ static inline byte @@ -561,20 +573,34 @@ 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; + char *fmt; 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", + if (!config_fetch(d, where + PCI_HT_PRI_LCTR0, PCI_HT_PRI_SIZEOF - PCI_HT_PRI_LCTR0)) + return; + rid = get_conf_byte(d, where + PCI_HT_PRI_RID); + if (rid < 0x23 && rid > 0x11) + printf("\t!!! Possibly incomplete decoding\n"); + + if (rid >= 0x23) + fmt = "\t\tCommand: BaseUnitID=%u UnitCnt=%u MastHost%c DefDir%c DUL%c\n"; + else + fmt = "\t\tCommand: BaseUnitID=%u UnitCnt=%u MastHost%c DefDir%c\n"; + printf(fmt, (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 = 0x23) + fmt = "\t\tLink Control 0: CFlE%c CST%c CFE%c = 0x23) + fmt = "\t\tLink Config 0: MLWI=%1$s DwFcIn%5$c MLWO=%2$s DwFcOut%6$c LWI=%3$s DwFcInEn%7$c LWO=%4$s DwFcOutEn%8$c\n"; + else + fmt = "\t\tLink Config 0: MLWI=%s MLWO=%s LWI=%s LWO=%s\n"; + printf(fmt, 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_DFI), + FLAG(lcnf0, PCI_HT_LCNF_DFO), + FLAG(lcnf0, PCI_HT_LCNF_DFIE), 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 = 0x23) + fmt = "\t\tLink Control 1: CFlE%c CST%c CFE%c = 0x23) + fmt = "\t\tLink Config 1: MLWI=%1$s DwFcIn%5$c MLWO=%2$s DwFcOut%6$c LWI=%3$s DwFcInEn%7$c LWO=%4$s DwFcOutEn%8$c\n"; + else + fmt = "\t\tLink Config 1: MLWI=%s MLWO=%s LWI=%s LWO=%s\n"; + printf(fmt, 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_DFI), + FLAG(lcnf1, PCI_HT_LCNF_DFO), + FLAG(lcnf1, PCI_HT_LCNF_DFIE), 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)); + if (rid < 0x23) + return; 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: 0x11) + printf("\t!!! Possibly incomplete decoding\n"); + + if (rid >= 0x23) + fmt = "\t\tCommand: WarmRst%c DblEnd%c DevNum=%u ChainSide%c HostHide%c Slave%c > 2, @@ -716,9 +766,12 @@ show_ht_sec(struct device *d, int where, int cmd) 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 = 0x23) + fmt = "\t\tLink Control: CFlE%c CST%c CFE%c = 0x23) + fmt = "\t\tLink Config: MLWI=%1$s DwFcIn%5$c MLWO=%2$s DwFcOut%6$c LWI=%3$s DwFcInEn%7$c LWO=%4$s DwFcOutEn%8$c\n"; + else + fmt = "\t\tLink Config: MLWI=%s MLWO=%s LWI=%s LWO=%s\n"; + printf(fmt, 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_DFI), + FLAG(lcnf, PCI_HT_LCNF_DFO), + FLAG(lcnf, PCI_HT_LCNF_DFIE), 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)); + if (rid < 0x23) + return; 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: > 3)) - 1, + FLAG(t, PCI_EXP_DEVCAP_EXT_TAG)); + printf("\t\tDevice: Latency L0s %s, L1 %s\n", + latency_l0s((t & PCI_EXP_DEVCAP_L0S) >> 6), + latency_l1((t & PCI_EXP_DEVCAP_L1) >> 9)); + if ((type == PCI_EXP_TYPE_ENDPOINT) || (type == PCI_EXP_TYPE_LEG_END) || + (type == PCI_EXP_TYPE_UPSTREAM) || (type == PCI_EXP_TYPE_PCI_BRIDGE)) + printf("\t\tDevice: AtnBtn%c AtnInd%c PwrInd%c\n", + FLAG(t, PCI_EXP_DEVCAP_ATN_BUT), + FLAG(t, PCI_EXP_DEVCAP_ATN_IND), FLAG(t, PCI_EXP_DEVCAP_PWR_IND)); + if (type == PCI_EXP_TYPE_UPSTREAM) + printf("\t\tDevice: SlotPowerLimit %f\n", + power_limit((t & PCI_EXP_DEVCAP_PWR_VAL) >> 18, + (t & PCI_EXP_DEVCAP_PWR_SCL) >> 26)); + + w = get_conf_word(d, where + PCI_EXP_DEVCTL); + printf("\t\tDevice: Errors: Correctable%c Non-Fatal%c Fatal%c Unsupported%c\n", + FLAG(w, PCI_EXP_DEVCTL_CERE), + FLAG(w, PCI_EXP_DEVCTL_NFERE), + FLAG(w, PCI_EXP_DEVCTL_FERE), + FLAG(w, PCI_EXP_DEVCTL_URRE)); + printf("\t\tDevice: RlxdOrd%c ExtTag%c PhantFunc%c AuxPwr%c NoSnoop%c\n", + FLAG(w, PCI_EXP_DEVCTL_RELAXED), + FLAG(w, PCI_EXP_DEVCTL_EXT_TAG), + FLAG(w, PCI_EXP_DEVCTL_PHANTOM), + FLAG(w, PCI_EXP_DEVCTL_AUX_PME), + FLAG(w, PCI_EXP_DEVCTL_NOSNOOP)); + printf("\t\tDevice: MaxPayload %d bytes, MaxReadReq %d bytes\n", + 128 << ((w & PCI_EXP_DEVCTL_PAYLOAD) >> 5), + 128 << ((w & PCI_EXP_DEVCTL_READRQ) >> 12)); +} + +static char *link_speed(int speed) +{ + switch (speed) + { + case 1: + return "2.5Gb/s"; + default: + return "unknown"; + } +} + +static char *aspm_support(int code) +{ + switch (code) + { + case 1: + return "L0s"; + case 3: + return "L0s L1"; + default: + return "unknown"; + } +} + +static const char *aspm_enabled(int code) +{ + static const char *desc[] = { "Disabled", "L0s Enabled", "L1 Enabled", "L0s L1 Enabled" }; + return desc[code]; +} + +static void show_express_link(struct device *d, int where, int type) +{ + u32 t; + u16 w; + + t = get_conf_long(d, where + PCI_EXP_LNKCAP); + printf("\t\tLink: Supported Speed %s, Width x%d, ASPM %s, Port %d\n", + link_speed(t & PCI_EXP_LNKCAP_SPEED), (t & PCI_EXP_LNKCAP_WIDTH) >> 4, + aspm_support((t & PCI_EXP_LNKCAP_ASPM) >> 10), + t >> 24); + printf("\t\tLink: Latency L0s %s, L1 %s\n", + latency_l0s((t & PCI_EXP_LNKCAP_L0S) >> 12), + latency_l1((t & PCI_EXP_LNKCAP_L1) >> 15)); + w = get_conf_word(d, where + PCI_EXP_LNKCTL); + printf("\t\tLink: ASPM %s", aspm_enabled(w & PCI_EXP_LNKCTL_ASPM)); + if ((type == PCI_EXP_TYPE_ROOT_PORT) || (type == PCI_EXP_TYPE_ENDPOINT) || + (type == PCI_EXP_TYPE_LEG_END)) + printf(" RCB %d bytes", w & PCI_EXP_LNKCTL_RCB ? 128 : 64); + if (w & PCI_EXP_LNKCTL_DISABLE) + printf(" Disabled"); + printf(" CommClk%c ExtSynch%c\n", FLAG(w, PCI_EXP_LNKCTL_CLOCK), + FLAG(w, PCI_EXP_LNKCTL_XSYNCH)); + w = get_conf_word(d, where + PCI_EXP_LNKSTA); + printf("\t\tLink: Speed %s, Width x%d\n", + link_speed(t & PCI_EXP_LNKSTA_SPEED), (t & PCI_EXP_LNKSTA_WIDTH) >> 4); +} + +static const char *indicator(int code) +{ + static const char *names[] = { "Unknown", "On", "Blink", "Off" }; + return names[code]; +} + +static void show_express_slot(struct device *d, int where) +{ + u32 t; + u16 w; + + t = get_conf_long(d, where + PCI_EXP_SLTCAP); + printf("\t\tSlot: AtnBtn%c PwrCtrl%c MRL%c AtnInd%c PwrInd%c HotPlug%c Surpise%c\n", + FLAG(t, PCI_EXP_SLTCAP_ATNB), + FLAG(t, PCI_EXP_SLTCAP_PWRC), + FLAG(t, PCI_EXP_SLTCAP_MRL), + FLAG(t, PCI_EXP_SLTCAP_ATNI), + FLAG(t, PCI_EXP_SLTCAP_PWRI), + FLAG(t, PCI_EXP_SLTCAP_HPC), + FLAG(t, PCI_EXP_SLTCAP_HPS)); + printf("\t\tSlot: Number %d, PowerLimit %f\n", t >> 19, + power_limit((t & PCI_EXP_SLTCAP_PWR_VAL) >> 7, + (t & PCI_EXP_SLTCAP_PWR_SCL) >> 15)); + w = get_conf_word(d, where + PCI_EXP_SLTCTL); + printf("\t\tSlot: Enabled AtnBtn%c PwrFlt%c MRL%c PresDet%c CmdCplt%c HPIrq%c\n", + FLAG(w, PCI_EXP_SLTCTL_ATNB), + FLAG(w, PCI_EXP_SLTCTL_PWRF), + FLAG(w, PCI_EXP_SLTCTL_MRLS), + FLAG(w, PCI_EXP_SLTCTL_PRSD), + FLAG(w, PCI_EXP_SLTCTL_CMDC), + FLAG(w, PCI_EXP_SLTCTL_HPIE)); + printf("\t\tSlot: AttnInd %s, PwrInd %s, Power%c\n", + indicator((w & PCI_EXP_SLTCTL_ATNI) >> 6), + indicator((w & PCI_EXP_SLTCTL_PWRI) >> 8), + FLAG(w, w & PCI_EXP_SLTCTL_PWRC)); +} + +static void show_express_root(struct device *d, int where) +{ + u16 w = get_conf_word(d, where + PCI_EXP_RTCTL); + printf("\t\tRoot: Correctable%c Non-Fatal%c Fatal%c PME%c\n", + FLAG(w, PCI_EXP_RTCTL_SECEE), + FLAG(w, PCI_EXP_RTCTL_SENFEE), + FLAG(w, PCI_EXP_RTCTL_SEFEE), + FLAG(w, PCI_EXP_RTCTL_PMEIE)); +} + +static void +show_express(struct device *d, int where, int cap) +{ + int type = (cap & PCI_EXP_FLAGS_TYPE) >> 4; + int size; + int slot = 0; + + printf("Express "); + switch (type) + { + case PCI_EXP_TYPE_ENDPOINT: + printf("Endpoint"); + break; + case PCI_EXP_TYPE_LEG_END: + printf("Legacy Endpoint"); + break; + case PCI_EXP_TYPE_ROOT_PORT: + slot = cap & PCI_EXP_FLAGS_SLOT; + printf("Root Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT)); + break; + case PCI_EXP_TYPE_UPSTREAM: + printf("Upstream Port"); + break; + case PCI_EXP_TYPE_DOWNSTREAM: + slot = cap & PCI_EXP_FLAGS_SLOT; + printf("Downstream Port (Slot%c)", FLAG(cap, PCI_EXP_FLAGS_SLOT)); + break; + case PCI_EXP_TYPE_PCI_BRIDGE: + printf("PCI/PCI-X Bridge"); + break; + default: + printf("Unknown type"); + } + printf(" IRQ %d\n", (cap & PCI_EXP_FLAGS_IRQ) >> 9); + if (verbose < 2) + return; + + size = 16; + if (slot) + size = 24; + if (type == PCI_EXP_TYPE_ROOT_PORT) + size = 32; + if (!config_fetch(d, where + PCI_EXP_DEVCAP, size)) + return; + + show_express_dev(d, where, type); + show_express_link(d, where, type); + if (slot) + show_express_slot(d, where); + if (type == PCI_EXP_TYPE_ROOT_PORT) + show_express_root(d, where); +} + +static void +show_msix(struct device *d, int where, int cap) +{ + u32 off; + + printf("MSI-X: Enable%c Mask%c TabSize=%d\n", + FLAG(cap, PCI_MSIX_ENABLE), + FLAG(cap, PCI_MSIX_MASK), + (cap & PCI_MSIX_TABSIZE) + 1); + if (verbose < 2 || !config_fetch(d, where + PCI_MSIX_TABLE, 8)) + return; + + off = get_conf_long(d, where + PCI_MSIX_TABLE); + printf("\t\tVector table: BAR=%d offset=%08x\n", + off & PCI_MSIX_BIR, off & ~PCI_MSIX_BIR); + off = get_conf_long(d, where + PCI_MSIX_PBA); + printf("\t\tPBA: BAR=%d offset=%08x\n", + off & PCI_MSIX_BIR, off & ~PCI_MSIX_BIR); +} + static void show_slotid(int cap) { @@ -919,6 +1222,75 @@ show_slotid(int cap) chs); } +static void +show_aer(struct device *d, int where) +{ + printf("Advanced Error Reporting\n"); +} + +static void +show_vc(struct device *d, int where) +{ + printf("Virtual Channel\n"); +} + +static void +show_dsn(struct device *d, int where) +{ + u32 t1, t2; + if (!config_fetch(d, where + 4, 8)) + return; + t1 = get_conf_long(d, where + 4); + t2 = get_conf_long(d, where + 8); + printf("Device Serial Number %02x-%02x-%02x-%02x-%02x-%02x-%02x-%02x\n", + t1 & 0xff, (t1 >> 8) & 0xff, (t1 >> 16) & 0xff, t1 >> 24, + t2 & 0xff, (t2 >> 8) & 0xff, (t2 >> 16) & 0xff, t2 >> 24); +} + +static void +show_pb(struct device *d, int where) +{ + printf("Power Budgeting\n"); +} + +static void +show_ext_caps(struct device *d) +{ + int where = 0x100; + do + { + u32 header; + int id; + + if (!config_fetch(d, where, 4)) + break; + header = get_conf_long(d, where); + if (!header) + break; + id = header & 0xffff; + printf("\tCapabilities: [%03x] ", where); + switch (id) + { + case PCI_EXT_CAP_ID_AER: + show_aer(d, where); + break; + case PCI_EXT_CAP_ID_VC: + show_vc(d, where); + break; + case PCI_EXT_CAP_ID_DSN: + show_dsn(d, where); + break; + case PCI_EXT_CAP_ID_PB: + show_pb(d, where); + break; + default: + printf("Unknown (%d)\n", id); + break; + } + where = header >> 20; + } while (where); +} + static void show_caps(struct device *d) { @@ -966,12 +1338,25 @@ show_caps(struct device *d) case PCI_CAP_ID_HT: show_ht(d, where, cap); break; + case PCI_CAP_ID_VNDR: + show_vendor(); + break; + case PCI_CAP_ID_DBG: + show_debug(); + break; + case PCI_CAP_ID_EXP: + show_express(d, where, cap); + break; + case PCI_CAP_ID_MSIX: + show_msix(d, where, cap); + break; default: printf("#%02x [%04x]\n", id, cap); } where = next; } } + show_ext_caps(d); } static void