summaryrefslogtreecommitdiffstats
path: root/usr.sbin/pciconf
diff options
context:
space:
mode:
authorjhb <jhb@FreeBSD.org>2010-09-08 17:53:34 +0000
committerjhb <jhb@FreeBSD.org>2010-09-08 17:53:34 +0000
commit1ced550055bbbf1d777b684fca14e6885ab97da5 (patch)
tree788220e75b6e6190522ba47d96bb996476c20f1d /usr.sbin/pciconf
parentef26efcc4331a57025c028ad74d9572ada06730c (diff)
downloadFreeBSD-src-1ced550055bbbf1d777b684fca14e6885ab97da5.zip
FreeBSD-src-1ced550055bbbf1d777b684fca14e6885ab97da5.tar.gz
- 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
Diffstat (limited to 'usr.sbin/pciconf')
-rw-r--r--usr.sbin/pciconf/cap.c95
1 files changed, 95 insertions, 0 deletions
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 <sys/systm.h>. */
+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);
+ }
}
OpenPOWER on IntegriCloud