From 1ced550055bbbf1d777b684fca14e6885ab97da5 Mon Sep 17 00:00:00 2001 From: jhb Date: Wed, 8 Sep 2010 17:53:34 +0000 Subject: - Add register definitions related to extended capability IDs in PCI-express. I used PCIZ_* for ID constants (plain capability IDs use PCIY_*). - Add register definitions for the Advanced Error Reporting, Virtual Channels, and Device Serial Number extended capabilities. - Teach pciconf -c to list extended as well as plain capabilities. Adds more detailed parsing for AER, VC, and device serial numbers. MFC after: 2 weeks --- usr.sbin/pciconf/cap.c | 95 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 95 insertions(+) (limited to 'usr.sbin/pciconf') diff --git a/usr.sbin/pciconf/cap.c b/usr.sbin/pciconf/cap.c index 473ed01..f324321 100644 --- a/usr.sbin/pciconf/cap.c +++ b/usr.sbin/pciconf/cap.c @@ -45,6 +45,8 @@ static const char rcsid[] = #include "pciconf.h" +static void list_ecaps(int fd, struct pci_conf *p); + static void cap_power(int fd, struct pci_conf *p, uint8_t ptr) { @@ -530,4 +532,97 @@ list_caps(int fd, struct pci_conf *p) printf("\n"); ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); } + + list_ecaps(fd, p); +} + +/* From . */ +static __inline uint32_t +bitcount32(uint32_t x) +{ + + x = (x & 0x55555555) + ((x & 0xaaaaaaaa) >> 1); + x = (x & 0x33333333) + ((x & 0xcccccccc) >> 2); + x = (x + (x >> 4)) & 0x0f0f0f0f; + x = (x + (x >> 8)); + x = (x + (x >> 16)) & 0x000000ff; + return (x); +} + +static void +ecap_aer(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) +{ + uint32_t sta, mask; + + printf("AER %d", ver); + if (ver != 1) + return; + sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_STATUS, 4); + mask = read_config(fd, &p->pc_sel, ptr + PCIR_AER_UC_SEVERITY, 4); + printf(" %d fatal", bitcount32(sta & mask)); + printf(" %d non-fatal", bitcount32(sta & ~mask)); + sta = read_config(fd, &p->pc_sel, ptr + PCIR_AER_COR_STATUS, 4); + printf(" %d corrected", bitcount32(sta)); +} + +static void +ecap_vc(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) +{ + uint32_t cap1; + + printf("VC %d", ver); + if (ver != 1) + return; + cap1 = read_config(fd, &p->pc_sel, ptr + PCIR_VC_CAP1, 4); + printf(" max VC%d", cap1 & PCIM_VC_CAP1_EXT_COUNT); + if ((cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) != 0) + printf(" lowpri VC0-VC%d", + (cap1 & PCIM_VC_CAP1_LOWPRI_EXT_COUNT) >> 4); +} + +static void +ecap_sernum(int fd, struct pci_conf *p, uint16_t ptr, uint8_t ver) +{ + uint32_t high, low; + + printf("Serial %d", ver); + if (ver != 1) + return; + low = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_LOW, 4); + high = read_config(fd, &p->pc_sel, ptr + PCIR_SERIAL_HIGH, 4); + printf(" %08x%08x", high, low); +} + +static void +list_ecaps(int fd, struct pci_conf *p) +{ + uint32_t ecap; + uint16_t ptr; + + ptr = PCIR_EXTCAP; + ecap = read_config(fd, &p->pc_sel, ptr, 4); + if (ecap == 0xffffffff || ecap == 0) + return; + for (;;) { + printf("ecap %04x[%03x] = ", PCI_EXTCAP_ID(ecap), ptr); + switch (PCI_EXTCAP_ID(ecap)) { + case PCIZ_AER: + ecap_aer(fd, p, ptr, PCI_EXTCAP_VER(ecap)); + break; + case PCIZ_VC: + ecap_vc(fd, p, ptr, PCI_EXTCAP_VER(ecap)); + break; + case PCIZ_SERNUM: + ecap_sernum(fd, p, ptr, PCI_EXTCAP_VER(ecap)); + break; + default: + printf("unknown %d", PCI_EXTCAP_VER(ecap)); + break; + } + printf("\n"); + ptr = PCI_EXTCAP_NEXTPTR(ecap); + if (ptr == 0) + break; + ecap = read_config(fd, &p->pc_sel, ptr, 4); + } } -- cgit v1.1