Index: sys/dev/pci/pcireg.h =================================================================== RCS file: /host/cvs/usr/cvs/src/sys/dev/pci/pcireg.h,v retrieving revision 1.57 diff -u -r1.57 pcireg.h --- sys/dev/pci/pcireg.h 19 Jan 2007 22:37:52 -0000 1.57 +++ sys/dev/pci/pcireg.h 20 Jan 2007 16:05:31 -0000 @@ -506,9 +506,31 @@ #define PCIR_HTMSI_ADDRESS_LO 0x4 #define PCIR_HTMSI_ADDRESS_HI 0x8 +/* PCI Vendor capability definitions */ +#define PCIR_VENDOR_LENGTH 0x2 +#define PCIR_VENDOR_DATA 0x3 + +/* PCI EHCI Debug Port definitions */ +#define PCIR_DEBUG_PORT 0x2 +#define PCIM_DEBUG_PORT_OFFSET 0x1FFF +#define PCIM_DEBUG_PORT_BAR 0xe000 + /* PCI-PCI Bridge Subvendor definitions */ #define PCIR_SUBVENDCAP_ID 0x4 +/* PCI Express definitions */ +#define PCIR_EXPRESS_FLAGS 0x2 +#define PCIM_EXP_FLAGS_VERSION 0x000F +#define PCIM_EXP_FLAGS_TYPE 0x00F0 +#define PCIM_EXP_TYPE_ENDPOINT 0x0000 +#define PCIM_EXP_TYPE_LEGACY_ENDPOINT 0x0010 +#define PCIM_EXP_TYPE_ROOT_PORT 0x0040 +#define PCIM_EXP_TYPE_UPSTREAM_PORT 0x0050 +#define PCIM_EXP_TYPE_DOWNSTREAM_PORT 0x0060 +#define PCIM_EXP_TYPE_PCI_BRIDGE 0x0070 +#define PCIM_EXP_FLAGS_SLOT 0x0100 +#define PCIM_EXP_FLAGS_IRQ 0x3e00 + /* MSI-X definitions */ #define PCIR_MSIX_CTRL 0x2 #define PCIM_MSIXCTRL_MSIX_ENABLE 0x8000 Index: usr.sbin/pciconf/pciconf.c =================================================================== RCS file: /host/cvs/usr/cvs/src/usr.sbin/pciconf/pciconf.c,v retrieving revision 1.26 diff -u -r1.26 pciconf.c --- usr.sbin/pciconf/pciconf.c 18 Aug 2005 11:11:40 -0000 1.26 +++ usr.sbin/pciconf/pciconf.c 20 Jan 2007 16:05:31 -0000 @@ -40,9 +40,11 @@ #include #include #include +#include #include #include +#include #include #include "pathnames.h" @@ -64,7 +66,8 @@ TAILQ_HEAD(,pci_vendor_info) pci_vendors; -static void list_devs(int vendors); +static void list_caps(int fd, struct pci_conf *p); +static void list_devs(int verbose, int caps); static void list_verbose(struct pci_conf *p); static char *guess_class(struct pci_conf *p); static char *guess_subclass(struct pci_conf *p); @@ -79,7 +82,7 @@ usage() { fprintf(stderr, "%s\n%s\n%s\n%s\n", - "usage: pciconf -l [-v]", + "usage: pciconf -l [-cv]", " pciconf -a selector", " pciconf -r [-b | -h] selector addr[:addr2]", " pciconf -w [-b | -h] selector addr value"); @@ -90,17 +93,21 @@ main(int argc, char **argv) { int c; - int listmode, readmode, writemode, attachedmode, verbose; + int listmode, readmode, writemode, attachedmode, caps, verbose; int byte, isshort; - listmode = readmode = writemode = attachedmode = verbose = byte = isshort = 0; + listmode = readmode = writemode = attachedmode = caps = verbose = byte = isshort = 0; - while ((c = getopt(argc, argv, "alrwbhv")) != -1) { + while ((c = getopt(argc, argv, "aclrwbhv")) != -1) { switch(c) { case 'a': attachedmode = 1; break; + case 'c': + caps = 1; + break; + case 'l': listmode = 1; break; @@ -137,7 +144,7 @@ usage(); if (listmode) { - list_devs(verbose); + list_devs(verbose, caps); } else if (attachedmode) { chkattached(argv[optind], byte ? 1 : isshort ? 2 : 4); @@ -155,7 +162,7 @@ } static void -list_devs(int verbose) +list_devs(int verbose, int caps) { int fd; struct pci_conf_io pc; @@ -165,7 +172,7 @@ if (verbose) load_vendors(); - fd = open(_PATH_DEVPCI, O_RDONLY, 0); + fd = open(_PATH_DEVPCI, caps ? O_RDWR : O_RDONLY, 0); if (fd < 0) err(1, "%s", _PATH_DEVPCI); @@ -212,6 +219,8 @@ p->pc_revid, p->pc_hdr); if (verbose) list_verbose(p); + if (caps) + list_caps(fd, p); } } while (pc.status == PCI_GETCONF_MORE_DEVS); @@ -227,7 +236,7 @@ TAILQ_FOREACH(vi, &pci_vendors, link) { if (vi->id == p->pc_vendor) { - printf(" vendor = '%s'\n", vi->desc); + printf(" vendor = '%s'\n", vi->desc); break; } } @@ -236,15 +245,15 @@ } else { TAILQ_FOREACH(di, &vi->devs, link) { if (di->id == p->pc_device) { - printf(" device = '%s'\n", di->desc); + printf(" device = '%s'\n", di->desc); break; } } } if ((dp = guess_class(p)) != NULL) - printf(" class = %s\n", dp); + printf(" class = %s\n", dp); if ((dp = guess_subclass(p)) != NULL) - printf(" subclass = %s\n", dp); + printf(" subclass = %s\n", dp); } /* @@ -458,6 +467,452 @@ return(error); } +static uint32_t +read_config(int fd, struct pcisel *sel, long reg, int width) +{ + struct pci_io pi; + + pi.pi_sel = *sel; + pi.pi_reg = reg; + pi.pi_width = width; + + if (ioctl(fd, PCIOCREAD, &pi) < 0) + err(1, "ioctl(PCIOCREAD)"); + + return (pi.pi_data); +} + +static void +cap_power(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint16_t cap, status; + + cap = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_CAP, 2); + status = read_config(fd, &p->pc_sel, ptr + PCIR_POWER_STATUS, 2); + printf("powerspec %d supports D0%s%s D3 current D%d", + cap & PCIM_PCAP_SPEC, + cap & PCIM_PCAP_D1SUPP ? " D1" : "", + cap & PCIM_PCAP_D2SUPP ? " D2" : "", + status & PCIM_PSTAT_DMASK); +} + +static void +cap_agp(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t status, command; + + status = read_config(fd, &p->pc_sel, ptr + AGP_STATUS, 4); + command = read_config(fd, &p->pc_sel, ptr + AGP_CAPID, 4); + printf("AGP "); + if (AGP_MODE_GET_MODE_3(status)) { + printf("v3 "); + if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_8x) + printf("8x "); + if (AGP_MODE_GET_RATE(status) & AGP_MODE_V3_RATE_4x) + printf("4x "); + } else { + if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_4x) + printf("4x "); + if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_2x) + printf("2x "); + if (AGP_MODE_GET_RATE(status) & AGP_MODE_V2_RATE_1x) + printf("1x "); + } + if (AGP_MODE_GET_SBA(status)) + printf("SBA "); + if (AGP_MODE_GET_AGP(command)) { + printf("enabled at "); + if (AGP_MODE_GET_MODE_3(command)) { + printf("v3 "); + switch (AGP_MODE_GET_RATE(command)) { + case AGP_MODE_V3_RATE_8x: + printf("8x "); + break; + case AGP_MODE_V3_RATE_4x: + printf("4x "); + break; + } + } else + switch (AGP_MODE_GET_RATE(command)) { + case AGP_MODE_V2_RATE_4x: + printf("4x "); + break; + case AGP_MODE_V2_RATE_2x: + printf("2x "); + break; + case AGP_MODE_V2_RATE_1x: + printf("1x "); + break; + } + if (AGP_MODE_GET_SBA(command)) + printf("SBA "); + } else + printf("disabled"); +} + +static void +cap_vpd(int fd, struct pci_conf *p, uint8_t ptr) +{ + + printf("VPD"); +} + +static void +cap_msi(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint16_t ctrl; + int msgnum; + + ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSI_CTRL, 2); + msgnum = 1 << ((ctrl & PCIM_MSICTRL_MMC_MASK) >> 1); + printf("MSI supports %d message%s%s%s ", msgnum, + (msgnum == 1) ? "" : "s", + (ctrl & PCIM_MSICTRL_64BIT) ? ", 64 bit" : "", + (ctrl & PCIM_MSICTRL_VECTOR) ? ", vector masks" : ""); + if (ctrl & PCIM_MSICTRL_MSI_ENABLE) { + msgnum = 1 << ((ctrl & PCIM_MSICTRL_MME_MASK) >> 4); + printf("enabled with %d message%s", msgnum, + (msgnum == 1) ? "" : "s"); + } +} + +static void +cap_pcix(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t status; + int comma, max_splits, max_burst_read; + + status = read_config(fd, &p->pc_sel, ptr + PCIXR_STATUS, 4); + printf("PCI-X "); + if (status & PCIXM_STATUS_64BIT) + printf("64-bit "); + if (p->pc_hdr & PCIM_HDRTYPE == 1) + printf("bridge "); + printf("supports"); + comma = 0; + if (status & PCIXM_STATUS_133CAP) { + printf("%s 133MHz", comma ? "," : ""); + comma = 1; + } + if (status & PCIXM_STATUS_266CAP) { + printf("%s 266MHz", comma ? "," : ""); + comma = 1; + } + if (status & PCIXM_STATUS_533CAP) { + printf("%s 533MHz", comma ? "," : ""); + comma = 1; + } + if (p->pc_hdr & PCIM_HDRTYPE == 1) + return; + switch (status & PCIXM_STATUS_MAX_READ) { + case PCIXM_STATUS_MAX_READ_512: + max_burst_read = 512; + break; + case PCIXM_STATUS_MAX_READ_1024: + max_burst_read = 1024; + break; + case PCIXM_STATUS_MAX_READ_2048: + max_burst_read = 2048; + break; + case PCIXM_STATUS_MAX_READ_4096: + max_burst_read = 4096; + break; + } + switch (status & PCIXM_STATUS_MAX_SPLITS) { + case PCIXM_STATUS_MAX_SPLITS_1: + max_splits = 1; + break; + case PCIXM_STATUS_MAX_SPLITS_2: + max_splits = 2; + break; + case PCIXM_STATUS_MAX_SPLITS_3: + max_splits = 3; + break; + case PCIXM_STATUS_MAX_SPLITS_4: + max_splits = 4; + break; + case PCIXM_STATUS_MAX_SPLITS_8: + max_splits = 8; + break; + case PCIXM_STATUS_MAX_SPLITS_12: + max_splits = 12; + break; + case PCIXM_STATUS_MAX_SPLITS_16: + max_splits = 16; + break; + case PCIXM_STATUS_MAX_SPLITS_32: + max_splits = 32; + break; + } + printf(" %d burst read, %d split transactions", max_burst_read, + max_splits); +} + +static void +cap_ht(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t reg; + uint16_t command; + + command = read_config(fd, &p->pc_sel, ptr + PCIR_HT_COMMAND, 2); + printf("HT "); + if ((command & 0xe000) == PCIM_HTCAP_SLAVE) + printf("slave"); + else if ((command & 0xe000) == PCIM_HTCAP_HOST) + printf("host"); + else + switch (command & PCIM_HTCMD_CAP_MASK) { + case PCIM_HTCAP_SWITCH: + printf("switch"); + break; + case PCIM_HTCAP_INTERRUPT: + printf("interrupt"); + break; + case PCIM_HTCAP_REVISION_ID: + printf("revision ID"); + break; + case PCIM_HTCAP_UNITID_CLUMPING: + printf("unit ID clumping"); + break; + case PCIM_HTCAP_EXT_CONFIG_SPACE: + printf("extended config space"); + break; + case PCIM_HTCAP_ADDRESS_MAPPING: + printf("address mapping"); + break; + case PCIM_HTCAP_MSI_MAPPING: + printf("MSI address window %s at 0x", + command & PCIM_HTCMD_MSI_ENABLE ? "enabled" : + "disabled"); + reg = read_config(fd, &p->pc_sel, + ptr + PCIR_HTMSI_ADDRESS_HI, 4); + if (reg != 0) + printf("08x", reg); + reg = read_config(fd, &p->pc_sel, + ptr + PCIR_HTMSI_ADDRESS_LO, 4); + printf("08x", reg); + break; + case PCIM_HTCAP_DIRECT_ROUTE: + printf("direct route"); + break; + case PCIM_HTCAP_VCSET: + printf("VC set"); + break; + case PCIM_HTCAP_RETRY_MODE: + printf("retry mode"); + break; + default: + printf("unknown %02x", command); + break; + } +} + +static void +cap_vendor(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint8_t length; + + length = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_LENGTH, 1); + printf("vendor (length %d)", length); + if (p->pc_vendor == 0x8086) { + /* Intel */ + uint8_t version; + + version = read_config(fd, &p->pc_sel, ptr + PCIR_VENDOR_DATA, + 1); + printf(" Intel cap %d version %d", version >> 4, version & 0xf); + if (version >> 4 == 1 && length == 12) { + /* Feature Detection */ + uint32_t fvec; + int comma; + + comma = 0; + fvec = read_config(fd, &p->pc_sel, ptr + + PCIR_VENDOR_DATA + 5, 4); + printf("\n\t\t features:"); + if (fvec & (1 << 0)) { + printf(" AMT"); + comma = 1; + } + fvec = read_config(fd, &p->pc_sel, ptr + + PCIR_VENDOR_DATA + 1, 4); + if (fvec & (1 << 21)) { + printf("%s Quick Resume", comma ? "," : ""); + comma = 1; + } + if (fvec & (1 << 18)) { + printf("%s SATA RAID-5", comma ? "," : ""); + comma = 1; + } + if (fvec & (1 << 9)) { + printf("%s Mobile", comma ? "," : ""); + comma = 1; + } + if (fvec & (1 << 7)) { + printf("%s 6 PCI-e x1 slots", comma ? "," : ""); + comma = 1; + } else { + printf("%s 4 PCI-e x1 slots", comma ? "," : ""); + comma = 1; + } + if (fvec & (1 << 5)) { + printf("%s SATA RAID-0/1/10", comma ? "," : ""); + comma = 1; + } + if (fvec & (1 << 3)) { + printf("%s SATA AHCI", comma ? "," : ""); + comma = 1; + } + } + } +} + +static void +cap_debug(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint16_t debug_port; + + debug_port = read_config(fd, &p->pc_sel, ptr + PCIR_DEBUG_PORT, 2); + printf("Debug Port at offset 0x%x in map 0x%x", debug_port & + PCIM_DEBUG_PORT_OFFSET, PCIR_BAR(debug_port >> 13)); +} + +static void +cap_subvendor(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t id; + + id = read_config(fd, &p->pc_sel, ptr + PCIR_SUBVENDCAP_ID, 4); + printf("PCI Bridge card=0x%08x", id); +} + +static void +cap_express(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint16_t flags; + + flags = read_config(fd, &p->pc_sel, ptr + PCIR_EXPRESS_FLAGS, 2); + printf("PCI-Express %d ", flags & PCIM_EXP_FLAGS_VERSION); + switch (flags & PCIM_EXP_FLAGS_TYPE) { + case PCIM_EXP_TYPE_ENDPOINT: + printf("endpoint"); + break; + case PCIM_EXP_TYPE_LEGACY_ENDPOINT: + printf("legacy endpoint"); + break; + case PCIM_EXP_TYPE_ROOT_PORT: + printf("root port"); + break; + case PCIM_EXP_TYPE_UPSTREAM_PORT: + printf("upstream port"); + break; + case PCIM_EXP_TYPE_DOWNSTREAM_PORT: + printf("downstream port"); + break; + case PCIM_EXP_TYPE_PCI_BRIDGE: + printf("PCI bridge"); + break; + default: + printf("type %d", (flags & PCIM_EXP_FLAGS_TYPE) >> 8); + break; + } + if (flags & PCIM_EXP_FLAGS_IRQ) + printf(" IRQ %d", (flags & PCIM_EXP_FLAGS_IRQ) >> 17); +} + +static void +cap_msix(int fd, struct pci_conf *p, uint8_t ptr) +{ + uint32_t val; + uint16_t ctrl; + int msgnum, table_bar, pba_bar; + + ctrl = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_CTRL, 2); + msgnum = (ctrl & PCIM_MSIXCTRL_TABLE_SIZE) + 1; + val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_TABLE, 4); + table_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); + val = read_config(fd, &p->pc_sel, ptr + PCIR_MSIX_PBA, 4); + pba_bar = PCIR_BAR(val & PCIM_MSIX_BIR_MASK); + printf("MSI-X supports %d message%s ", msgnum, + (msgnum == 1) ? "" : "s"); + if (table_bar == pba_bar) + printf("in map 0x%x", table_bar); + else + printf("in maps 0x%x and 0x%x", table_bar, pba_bar); + if (ctrl & PCIM_MSIXCTRL_MSIX_ENABLE) + printf(" enabled"); +} + +static void +list_caps(int fd, struct pci_conf *p) +{ + uint16_t cmd; + uint8_t ptr, cap; + + /* Are capabilities present for this device? */ + cmd = read_config(fd, &p->pc_sel, PCIR_STATUS, 2); + if (!(cmd & PCIM_STATUS_CAPPRESENT)) + return; + + switch (p->pc_hdr & PCIM_HDRTYPE) { + case 0: + case 1: + ptr = PCIR_CAP_PTR; + break; + case 2: + ptr = PCIR_CAP_PTR_2; + break; + default: + errx(1, "list_caps: bad header type"); + } + + /* Walk the capability list. */ + ptr = read_config(fd, &p->pc_sel, ptr, 1); + while (ptr != 0 && ptr != 0xff) { + cap = read_config(fd, &p->pc_sel, ptr + PCICAP_ID, 1); + printf(" cap %02x[%02x] = ", cap, ptr); + switch (cap) { + case PCIY_PMG: + cap_power(fd, p, ptr); + break; + case PCIY_AGP: + cap_agp(fd, p, ptr); + break; + case PCIY_VPD: + cap_vpd(fd, p, ptr); + break; + case PCIY_MSI: + cap_msi(fd, p, ptr); + break; + case PCIY_PCIX: + cap_pcix(fd, p, ptr); + break; + case PCIY_HT: + cap_ht(fd, p, ptr); + break; + case PCIY_VENDOR: + cap_vendor(fd, p, ptr); + break; + case PCIY_DEBUG: + cap_debug(fd, p, ptr); + break; + case PCIY_SUBVENDOR: + cap_subvendor(fd, p, ptr); + break; + case PCIY_EXPRESS: + cap_express(fd, p, ptr); + break; + case PCIY_MSIX: + cap_msix(fd, p, ptr); + break; + default: + printf("unknown"); + break; + } + printf("\n"); + ptr = read_config(fd, &p->pc_sel, ptr + PCICAP_NEXTPTR, 1); + } +} static struct pcisel getsel(const char *str) @@ -496,16 +951,8 @@ static void readone(int fd, struct pcisel *sel, long reg, int width) { - struct pci_io pi; - - pi.pi_sel = *sel; - pi.pi_reg = reg; - pi.pi_width = width; - - if (ioctl(fd, PCIOCREAD, &pi) < 0) - err(1, "ioctl(PCIOCREAD)"); - printf("%0*x", width*2, pi.pi_data); + printf("%0*x", width*2, read_config(fd, sel, reg, width)); } static void @@ -559,7 +1006,7 @@ } static void -chkattached (const char *name, int width) +chkattached(const char *name, int width) { int fd; struct pci_io pi;