1*e6c7c102Sjsg /* $OpenBSD: pcidump.c,v 1.71 2024/04/23 13:34:51 jsg Exp $ */
255e5c1e0Sjasper
31f680598Sdlg /*
432891a67Sdlg * Copyright (c) 2006, 2007 David Gwynne <loki@animata.net>
51f680598Sdlg *
61f680598Sdlg * Permission to use, copy, modify, and distribute this software for any
71f680598Sdlg * purpose with or without fee is hereby granted, provided that the above
81f680598Sdlg * copyright notice and this permission notice appear in all copies.
91f680598Sdlg *
101f680598Sdlg * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
111f680598Sdlg * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
121f680598Sdlg * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
131f680598Sdlg * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
141f680598Sdlg * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
151f680598Sdlg * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
161f680598Sdlg * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
171f680598Sdlg */
181f680598Sdlg
19b9fc9a72Sderaadt #include <sys/types.h>
20271b14d7Schl #include <sys/ioctl.h>
211f680598Sdlg #include <sys/pciio.h>
228b86f50eSkettenis
233025e2fbSotto #include <stdio.h> /* need NULL for dev/pci/ headers */
2471073a54Sguenther
251f680598Sdlg #include <dev/pci/pcireg.h>
261f680598Sdlg #include <dev/pci/pcidevs.h>
271f680598Sdlg #include <dev/pci/pcidevs_data.h>
281f680598Sdlg
298b86f50eSkettenis #include <err.h>
308b86f50eSkettenis #include <errno.h>
318b86f50eSkettenis #include <fcntl.h>
328b86f50eSkettenis #include <paths.h>
338b86f50eSkettenis #include <stdlib.h>
348b86f50eSkettenis #include <string.h>
358b86f50eSkettenis #include <unistd.h>
36b9fc9a72Sderaadt #include <limits.h>
374b96984bSdlg #include <vis.h>
388b86f50eSkettenis
391f680598Sdlg #define PCIDEV "/dev/pci"
401f680598Sdlg
410054379cSkettenis #ifndef nitems
420054379cSkettenis #define nitems(_a) (sizeof((_a)) / sizeof((_a)[0]))
430054379cSkettenis #endif
440054379cSkettenis
451f680598Sdlg __dead void usage(void);
46ae624d2eSdlg void scanpcidomain(void);
471f680598Sdlg int probe(int, int, int);
481f680598Sdlg void dump(int, int, int);
496e862d19Skettenis void hexdump(int, int, int, int);
501f680598Sdlg const char *str2busdevfunc(const char *, int *, int *, int *);
511f680598Sdlg int pci_nfuncs(int, int);
521f680598Sdlg int pci_read(int, int, int, u_int32_t, u_int32_t *);
53d01993f3Skettenis int pci_readmask(int, int, int, u_int32_t, u_int32_t *);
544719bcb4Skettenis void dump_bars(int, int, int, int);
55b54d2ef8Sreyk void dump_caplist(int, int, int, u_int8_t);
564b96984bSdlg void dump_vpd(int, int, int);
573a2eabfeSkettenis void dump_pci_powerstate(int, int, int, uint8_t);
5858cbacc3Sjsg void dump_pcie_linkspeed(int, int, int, uint8_t);
591f43da81Sdlg void dump_pcie_devserial(int, int, int, uint16_t);
60dda8f56eSjmatthew void dump_msi(int, int, int, uint8_t);
61dda8f56eSjmatthew void dump_msix(int, int, int, uint8_t);
6258cbacc3Sjsg void print_pcie_ls(uint8_t);
632c15f759Skettenis int dump_rom(int, int, int);
648b86f50eSkettenis int dump_vga_bios(void);
651f680598Sdlg
6606b03c88Sdlg static const char *
6706b03c88Sdlg pci_class_name(pci_class_t);
6806b03c88Sdlg static const char *
6906b03c88Sdlg pci_subclass_name(pci_class_t, pci_subclass_t);
7006b03c88Sdlg
71311a3a94Sderaadt void dump_type0(int bus, int dev, int func);
72311a3a94Sderaadt void dump_type1(int bus, int dev, int func);
73311a3a94Sderaadt void dump_type2(int bus, int dev, int func);
74311a3a94Sderaadt
751f680598Sdlg __dead void
usage(void)761f680598Sdlg usage(void)
771f680598Sdlg {
7847851cc6Sderaadt extern char *__progname;
7947851cc6Sderaadt
80baede216Ssobrado fprintf(stderr,
818f524c6dSjmc "usage: %s [-v] [-x | -xx | -xxx] [-d pcidev] [bus:dev:func]\n"
82b07261cfSkettenis " %s -r file [-d pcidev] bus:dev:func\n",
83b07261cfSkettenis __progname, __progname);
841f680598Sdlg exit(1);
851f680598Sdlg }
861f680598Sdlg
87927c4f3eSderaadt int pcifd;
882c15f759Skettenis int romfd;
891f680598Sdlg int verbose = 0;
906e862d19Skettenis int hex = 0;
915d2ed882Skettenis int size = 64;
921f680598Sdlg
93b54d2ef8Sreyk const char *pci_capnames[] = {
94b54d2ef8Sreyk "Reserved",
95b54d2ef8Sreyk "Power Management",
96b54d2ef8Sreyk "AGP",
97b54d2ef8Sreyk "Vital Product Data (VPD)",
98b54d2ef8Sreyk "Slot Identification",
99a0404306Sdlg "Message Signalled Interrupts (MSI)",
100b54d2ef8Sreyk "CompactPCI Hot Swap",
101b54d2ef8Sreyk "PCI-X",
102b54d2ef8Sreyk "AMD LDT/HT",
103b54d2ef8Sreyk "Vendor Specific",
104b54d2ef8Sreyk "Debug Port",
105b54d2ef8Sreyk "CompactPCI Central Resource Control",
106b54d2ef8Sreyk "PCI Hot-Plug",
107b54d2ef8Sreyk "PCI-PCI",
108b54d2ef8Sreyk "AGP8",
109b54d2ef8Sreyk "Secure",
110b54d2ef8Sreyk "PCI Express",
111a0404306Sdlg "Extended Message Signalled Interrupts (MSI-X)",
11273746b6cSjsg "SATA",
1131e22210cSjsg "PCI Advanced Features",
1141e22210cSjsg "Enhanced Allocation",
1151e22210cSjsg "Flattening Portal Bridge",
116b54d2ef8Sreyk };
117b54d2ef8Sreyk
118f9804a94Sderaadt const char *pci_enhanced_capnames[] = {
119f9804a94Sderaadt "Unknown",
120f9804a94Sderaadt "Advanced Error Reporting",
121f9804a94Sderaadt "Virtual Channel Capability",
122f9804a94Sderaadt "Device Serial Number",
123f9804a94Sderaadt "Power Budgeting",
124f9804a94Sderaadt "Root Complex Link Declaration",
125f9804a94Sderaadt "Root Complex Internal Link Control",
126f9804a94Sderaadt "Root Complex Event Collector",
127f9804a94Sderaadt "Multi-Function VC Capability",
128f9804a94Sderaadt "Virtual Channel Capability",
129f9804a94Sderaadt "Root Complex/Root Bridge",
130f9804a94Sderaadt "Vendor-Specific",
131f9804a94Sderaadt "Config Access",
132f9804a94Sderaadt "Access Control Services",
133f9804a94Sderaadt "Alternate Routing ID",
134f9804a94Sderaadt "Address Translation Services",
135f9804a94Sderaadt "Single Root I/O Virtualization",
136f9804a94Sderaadt "Multi Root I/O Virtualization",
137f9804a94Sderaadt "Multicast",
138f9804a94Sderaadt "Page Request Interface",
139f9804a94Sderaadt "Reserved for AMD",
140f9804a94Sderaadt "Resizable BAR",
141f9804a94Sderaadt "Dynamic Power Allocation",
142f9804a94Sderaadt "TPH Requester",
143f9804a94Sderaadt "Latency Tolerance Reporting",
144f9804a94Sderaadt "Secondary PCIe Capability",
145f9804a94Sderaadt "Protocol Multiplexing",
146f9804a94Sderaadt "Process Address Space ID",
147ec0b2420Sjsg "LN Requester",
148f9804a94Sderaadt "Downstream Port Containment",
149d1a52e20Sjsg "L1 PM",
150f9804a94Sderaadt "Precision Time Measurement",
1511e22210cSjsg "PCI Express over M-PHY",
1521e22210cSjsg "FRS Queueing",
1531e22210cSjsg "Readiness Time Reporting",
1541e22210cSjsg "Designated Vendor-Specific",
1551e22210cSjsg "VF Resizable BAR",
1561e22210cSjsg "Data Link Feature ",
1571e22210cSjsg "Physical Layer 16.0 GT/s",
1581e22210cSjsg "Lane Margining at the Receiver",
1591e22210cSjsg "Hierarchy ID",
1601e22210cSjsg "Native PCIe Enclosure Management",
1611e22210cSjsg "Physical Layer 32.0 GT/s",
1621e22210cSjsg "Alternate Protocol",
1631e22210cSjsg "System Firmware Intermediary",
1641e22210cSjsg "Shadow Functions",
1651e22210cSjsg "Data Object Exchange",
1661e22210cSjsg "Device 3",
1671e22210cSjsg "Integrity and Data Encryption",
168f9804a94Sderaadt };
169f9804a94Sderaadt
1701f680598Sdlg int
main(int argc,char * argv[])1711f680598Sdlg main(int argc, char *argv[])
1721f680598Sdlg {
1731f680598Sdlg int nfuncs;
1741f680598Sdlg int bus, dev, func;
175b9fc9a72Sderaadt char pcidev[PATH_MAX] = PCIDEV;
1762c15f759Skettenis char *romfile = NULL;
1771f680598Sdlg const char *errstr;
178ae624d2eSdlg int c, error = 0, dumpall = 1, domid = 0;
1791f680598Sdlg
1802c15f759Skettenis while ((c = getopt(argc, argv, "d:r:vx")) != -1) {
1811f680598Sdlg switch (c) {
1821f680598Sdlg case 'd':
183ae624d2eSdlg strlcpy(pcidev, optarg, sizeof(pcidev));
184ae624d2eSdlg dumpall = 0;
1851f680598Sdlg break;
1862c15f759Skettenis case 'r':
1872c15f759Skettenis romfile = optarg;
1882c15f759Skettenis dumpall = 0;
1892c15f759Skettenis break;
1901f680598Sdlg case 'v':
1911f680598Sdlg verbose = 1;
1921f680598Sdlg break;
1936e862d19Skettenis case 'x':
1946e862d19Skettenis hex++;
1956e862d19Skettenis break;
1961f680598Sdlg default:
1971f680598Sdlg usage();
1981f680598Sdlg }
1991f680598Sdlg }
2001f680598Sdlg argc -= optind;
2011f680598Sdlg argv += optind;
2021f680598Sdlg
2032c15f759Skettenis if (argc > 1 || (romfile && argc != 1))
2041f680598Sdlg usage();
2051f680598Sdlg
2062c15f759Skettenis if (romfile) {
2072c15f759Skettenis romfd = open(romfile, O_WRONLY|O_CREAT|O_TRUNC, 0777);
2082c15f759Skettenis if (romfd == -1)
2092c15f759Skettenis err(1, "%s", romfile);
2102c15f759Skettenis }
2112c15f759Skettenis
212c8d17636Smestre if (unveil("/dev", "r") == -1)
213bc5a8259Sbeck err(1, "unveil /dev");
214c8d17636Smestre if (unveil(NULL, NULL) == -1)
215c8d17636Smestre err(1, "unveil");
216c8d17636Smestre
2175d2ed882Skettenis if (hex > 1)
2185d2ed882Skettenis size = 256;
2195d2ed882Skettenis if (hex > 2)
2205d2ed882Skettenis size = 4096;
2215d2ed882Skettenis
222ae624d2eSdlg if (argc == 1)
223ae624d2eSdlg dumpall = 0;
224ae624d2eSdlg
225ae624d2eSdlg if (dumpall == 0) {
226b7041c07Sderaadt pcifd = open(pcidev, O_RDONLY);
2271f680598Sdlg if (pcifd == -1)
2281f680598Sdlg err(1, "%s", pcidev);
229ae624d2eSdlg } else {
230ae624d2eSdlg for (;;) {
231ae624d2eSdlg snprintf(pcidev, 16, "/dev/pci%d", domid++);
232b7041c07Sderaadt pcifd = open(pcidev, O_RDONLY);
233ae624d2eSdlg if (pcifd == -1) {
234ae624d2eSdlg if (errno == ENXIO || errno == ENOENT) {
235ae624d2eSdlg return 0;
236ae624d2eSdlg } else {
237ae624d2eSdlg err(1, "%s", pcidev);
238ae624d2eSdlg }
239ae624d2eSdlg }
240ae624d2eSdlg printf("Domain %s:\n", pcidev);
241ae624d2eSdlg scanpcidomain();
242ae624d2eSdlg close(pcifd);
243ae624d2eSdlg }
244ae624d2eSdlg }
2451f680598Sdlg
2461f680598Sdlg if (argc == 1) {
2471f680598Sdlg errstr = str2busdevfunc(argv[0], &bus, &dev, &func);
2481f680598Sdlg if (errstr != NULL)
2491f680598Sdlg errx(1, "\"%s\": %s", argv[0], errstr);
2501f680598Sdlg
2511f680598Sdlg nfuncs = pci_nfuncs(bus, dev);
2521f680598Sdlg if (nfuncs == -1 || func > nfuncs)
2531f680598Sdlg error = ENXIO;
2542c15f759Skettenis else if (romfile)
2552c15f759Skettenis error = dump_rom(bus, dev, func);
2561f680598Sdlg else
2571f680598Sdlg error = probe(bus, dev, func);
2581f680598Sdlg
2591f680598Sdlg if (error != 0)
2605ad04d35Sguenther errc(1, error, "\"%s\"", argv[0]);
2611f680598Sdlg } else {
2622c15f759Skettenis printf("Domain %s:\n", pcidev);
263ae624d2eSdlg scanpcidomain();
264ae624d2eSdlg }
265ae624d2eSdlg
266ae624d2eSdlg return (0);
267ae624d2eSdlg }
268ae624d2eSdlg
269ae624d2eSdlg void
scanpcidomain(void)270ae624d2eSdlg scanpcidomain(void)
271ae624d2eSdlg {
272ae624d2eSdlg int nfuncs;
273ae624d2eSdlg int bus, dev, func;
274ae624d2eSdlg
2751f680598Sdlg for (bus = 0; bus < 256; bus++) {
2766334b9d1Stobias for (dev = 0; dev < 32; dev++) {
2771f680598Sdlg nfuncs = pci_nfuncs(bus, dev);
2786334b9d1Stobias for (func = 0; func < nfuncs; func++) {
2791f680598Sdlg probe(bus, dev, func);
2801f680598Sdlg }
2811f680598Sdlg }
2821f680598Sdlg }
2831f680598Sdlg }
2841f680598Sdlg
2851f680598Sdlg const char *
str2busdevfunc(const char * string,int * bus,int * dev,int * func)2861f680598Sdlg str2busdevfunc(const char *string, int *bus, int *dev, int *func)
2871f680598Sdlg {
2881f680598Sdlg const char *errstr;
2891f680598Sdlg char b[80], *d, *f;
2901f680598Sdlg
2911f680598Sdlg strlcpy(b, string, sizeof(b));
2921f680598Sdlg
2931f680598Sdlg d = strchr(b, ':');
2941f680598Sdlg if (d == NULL)
2951f680598Sdlg return("device not specified");
2961f680598Sdlg *d++ = '\0';
2971f680598Sdlg
2981f680598Sdlg f = strchr(d, ':');
2991f680598Sdlg if (f == NULL)
3001f680598Sdlg return("function not specified");
3011f680598Sdlg *f++ = '\0';
3021f680598Sdlg
3036334b9d1Stobias *bus = strtonum(b, 0, 255, &errstr);
3041f680598Sdlg if (errstr != NULL)
3051f680598Sdlg return (errstr);
3066334b9d1Stobias *dev = strtonum(d, 0, 31, &errstr);
3071f680598Sdlg if (errstr != NULL)
3081f680598Sdlg return (errstr);
3096334b9d1Stobias *func = strtonum(f, 0, 7, &errstr);
3101f680598Sdlg if (errstr != NULL)
3111f680598Sdlg return (errstr);
3121f680598Sdlg
3131f680598Sdlg return (NULL);
3141f680598Sdlg }
3151f680598Sdlg
3161f680598Sdlg int
probe(int bus,int dev,int func)3171f680598Sdlg probe(int bus, int dev, int func)
3181f680598Sdlg {
3191f680598Sdlg u_int32_t id_reg;
3201f680598Sdlg const struct pci_known_vendor *pkv;
3211f680598Sdlg const struct pci_known_product *pkp;
3221f680598Sdlg const char *vendor = NULL, *product = NULL;
3231f680598Sdlg
3241f680598Sdlg if (pci_read(bus, dev, func, PCI_ID_REG, &id_reg) != 0)
3251f680598Sdlg return (errno);
3261f680598Sdlg
3271f680598Sdlg if (PCI_VENDOR(id_reg) == PCI_VENDOR_INVALID ||
3281f680598Sdlg PCI_VENDOR(id_reg) == 0)
3291f680598Sdlg return (ENXIO);
3301f680598Sdlg
3311f680598Sdlg for (pkv = pci_known_vendors; pkv->vendorname != NULL; pkv++) {
3321f680598Sdlg if (pkv->vendor == PCI_VENDOR(id_reg)) {
3331f680598Sdlg vendor = pkv->vendorname;
3341f680598Sdlg break;
3351f680598Sdlg }
3361f680598Sdlg }
3371f680598Sdlg
3381f680598Sdlg if (vendor != NULL) {
3391f680598Sdlg for (pkp = pci_known_products; pkp->productname != NULL; pkp++)
3401f680598Sdlg if (pkp->vendor == PCI_VENDOR(id_reg) &&
3411f680598Sdlg pkp->product == PCI_PRODUCT(id_reg)) {
3421f680598Sdlg product = pkp->productname;
3431f680598Sdlg break;
3441f680598Sdlg }
3451f680598Sdlg }
3461f680598Sdlg
347d30d053eSdlg printf(" %d:%d:%d: %s %s\n", bus, dev, func,
3481f680598Sdlg (vendor == NULL) ? "unknown" : vendor,
3491f680598Sdlg (product == NULL) ? "unknown" : product);
3501f680598Sdlg
3511f680598Sdlg if (verbose)
3521f680598Sdlg dump(bus, dev, func);
3536e862d19Skettenis if (hex > 0)
3545d2ed882Skettenis hexdump(bus, dev, func, size);
3551f680598Sdlg
3561f680598Sdlg return (0);
3571f680598Sdlg }
3581f680598Sdlg
3594b96984bSdlg int
print_bytes(const uint8_t * buf,size_t len)3604b96984bSdlg print_bytes(const uint8_t *buf, size_t len)
3614b96984bSdlg {
3624b96984bSdlg char dst[8];
3634b96984bSdlg size_t i;
3644b96984bSdlg
3654b96984bSdlg for (i = 0; i < len; i++) {
3664b96984bSdlg vis(dst, buf[i], VIS_TAB|VIS_NL, 0);
3674b96984bSdlg printf("%s", dst);
3684b96984bSdlg }
3694b96984bSdlg printf("\n");
3704b96984bSdlg
3714b96984bSdlg return (0);
3724b96984bSdlg }
3734b96984bSdlg
3744b96984bSdlg int
print_vpd(const uint8_t * buf,size_t len)3754b96984bSdlg print_vpd(const uint8_t *buf, size_t len)
3764b96984bSdlg {
3774b96984bSdlg const struct pci_vpd *vpd;
3784b96984bSdlg char key0[8];
3794b96984bSdlg char key1[8];
380dcbed439Skn size_t vlen;
3814b96984bSdlg
3824b96984bSdlg while (len > 0) {
3834b96984bSdlg if (len < sizeof(*vpd))
3844b96984bSdlg return (1);
3854b96984bSdlg
3864b96984bSdlg vpd = (const struct pci_vpd *)buf;
3874b96984bSdlg vis(key0, vpd->vpd_key0, VIS_TAB|VIS_NL, 0);
3884b96984bSdlg vis(key1, vpd->vpd_key1, VIS_TAB|VIS_NL, 0);
3894b96984bSdlg vlen = vpd->vpd_len;
3904b96984bSdlg
3914b96984bSdlg printf("\t\t %s%s: ", key0, key1);
3924b96984bSdlg
3934b96984bSdlg buf += sizeof(*vpd);
3944b96984bSdlg len -= sizeof(*vpd);
3954b96984bSdlg
3964b96984bSdlg if (len < vlen)
3974b96984bSdlg return (1);
3984b96984bSdlg print_bytes(buf, vlen);
3994b96984bSdlg
4004b96984bSdlg buf += vlen;
4014b96984bSdlg len -= vlen;
4024b96984bSdlg }
4034b96984bSdlg
4044b96984bSdlg return (0);
4054b96984bSdlg }
4064b96984bSdlg
4074b96984bSdlg void
dump_vpd(int bus,int dev,int func)4084b96984bSdlg dump_vpd(int bus, int dev, int func)
4094b96984bSdlg {
4104b96984bSdlg struct pci_vpd_req io;
4114b96984bSdlg uint32_t data[64]; /* XXX this can be up to 32k of data */
4124b96984bSdlg uint8_t *buf = (uint8_t *)data;
4134b96984bSdlg size_t len = sizeof(data);
4144b96984bSdlg
4154b96984bSdlg bzero(&io, sizeof(io));
4164b96984bSdlg io.pv_sel.pc_bus = bus;
4174b96984bSdlg io.pv_sel.pc_dev = dev;
4184b96984bSdlg io.pv_sel.pc_func = func;
4194b96984bSdlg io.pv_offset = 0;
4204b96984bSdlg io.pv_count = nitems(data);
4214b96984bSdlg io.pv_data = data;
4224b96984bSdlg
423e1c925b0Sdlg if (ioctl(pcifd, PCIOCGETVPD, &io) == -1) {
4244b96984bSdlg warn("PCIOCGETVPD");
425e1c925b0Sdlg return;
426e1c925b0Sdlg }
4274b96984bSdlg
4284b96984bSdlg do {
4294b96984bSdlg uint8_t vpd = *buf;
4304b96984bSdlg uint8_t type;
4314b96984bSdlg size_t hlen, vlen;
4324b96984bSdlg int (*print)(const uint8_t *, size_t) = print_bytes;
4334b96984bSdlg
4344b96984bSdlg if (PCI_VPDRES_ISLARGE(vpd)) {
4354b96984bSdlg struct pci_vpd_largeres *res;
4364b96984bSdlg type = PCI_VPDRES_LARGE_NAME(vpd);
4374b96984bSdlg
4384b96984bSdlg switch (type) {
4394b96984bSdlg case PCI_VPDRES_TYPE_IDENTIFIER_STRING:
4404b96984bSdlg printf("\t\tProduct Name: ");
4414b96984bSdlg break;
4424b96984bSdlg case PCI_VPDRES_TYPE_VPD:
4434b96984bSdlg print = print_vpd;
4444b96984bSdlg break;
4454b96984bSdlg default:
4464b96984bSdlg printf("%02x: ", type);
4474b96984bSdlg break;
4484b96984bSdlg }
4494b96984bSdlg
4504b96984bSdlg if (len < sizeof(*res))
4514b96984bSdlg goto trunc;
4524b96984bSdlg res = (struct pci_vpd_largeres *)buf;
4534b96984bSdlg
4544b96984bSdlg hlen = sizeof(*res);
4554b96984bSdlg vlen = ((size_t)res->vpdres_len_msb << 8) |
4564b96984bSdlg (size_t)res->vpdres_len_lsb;
4574b96984bSdlg } else { /* small */
4584b96984bSdlg type = PCI_VPDRES_SMALL_NAME(vpd);
4594b96984bSdlg if (type == PCI_VPDRES_TYPE_END_TAG)
4604b96984bSdlg break;
4614b96984bSdlg
4624b96984bSdlg printf("\t\t");
4634b96984bSdlg switch (type) {
4644b96984bSdlg case PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID:
4654b96984bSdlg case PCI_VPDRES_TYPE_VENDOR_DEFINED:
4664b96984bSdlg default:
4674b96984bSdlg printf("%02x", type);
4684b96984bSdlg break;
4694b96984bSdlg }
4704b96984bSdlg
4714b96984bSdlg hlen = sizeof(vpd);
4724b96984bSdlg vlen = PCI_VPDRES_SMALL_LENGTH(vpd);
4734b96984bSdlg }
4744b96984bSdlg buf += hlen;
4754b96984bSdlg len -= hlen;
4764b96984bSdlg
4774b96984bSdlg if (len < vlen)
4784b96984bSdlg goto trunc;
4794b96984bSdlg (*print)(buf, vlen);
4804b96984bSdlg
4814b96984bSdlg buf += vlen;
4824b96984bSdlg len -= vlen;
4834b96984bSdlg } while (len > 0);
4844b96984bSdlg
4854b96984bSdlg return;
4864b96984bSdlg trunc:
4874b96984bSdlg /* i have spent too much time in tcpdump - dlg */
4884b96984bSdlg printf("[|vpd]\n");
4894b96984bSdlg }
4904b96984bSdlg
4911f680598Sdlg void
dump_pci_powerstate(int bus,int dev,int func,uint8_t ptr)4923a2eabfeSkettenis dump_pci_powerstate(int bus, int dev, int func, uint8_t ptr)
4933a2eabfeSkettenis {
4943a2eabfeSkettenis u_int32_t pmcsr;
4953a2eabfeSkettenis
4963a2eabfeSkettenis if (pci_read(bus, dev, func, ptr + PCI_PMCSR, &pmcsr) != 0)
4973a2eabfeSkettenis return;
4983a2eabfeSkettenis
499557040b2Sdlg printf("\t\tState: D%d", pmcsr & PCI_PMCSR_STATE_MASK);
5007b4098ebSkettenis if (pmcsr & PCI_PMCSR_PME_EN)
5017b4098ebSkettenis printf(" PME# enabled");
5027b4098ebSkettenis if (pmcsr & PCI_PMCSR_PME_STATUS)
5037b4098ebSkettenis printf(" PME# asserted");
5047b4098ebSkettenis printf("\n");
5053a2eabfeSkettenis }
5063a2eabfeSkettenis
5074adaa114Sdlg static unsigned int
pcie_dcap_mps(uint32_t dcap)5084adaa114Sdlg pcie_dcap_mps(uint32_t dcap)
5094adaa114Sdlg {
5104adaa114Sdlg uint32_t shift = dcap & 0x7;
5114adaa114Sdlg return (128 << shift);
5124adaa114Sdlg }
5134adaa114Sdlg
5144adaa114Sdlg static unsigned int
pcie_dcsr_mps(uint32_t dcsr)5154adaa114Sdlg pcie_dcsr_mps(uint32_t dcsr)
5164adaa114Sdlg {
5174adaa114Sdlg uint32_t shift = (dcsr >> 5) & 0x7;
5184adaa114Sdlg return (128 << shift);
5194adaa114Sdlg }
5204adaa114Sdlg
5214adaa114Sdlg static unsigned int
pcie_dcsr_mrrs(uint32_t dcsr)5224adaa114Sdlg pcie_dcsr_mrrs(uint32_t dcsr)
5234adaa114Sdlg {
5244adaa114Sdlg uint32_t shift = (dcsr >> 12) & 0x7;
5254adaa114Sdlg return (128 << shift);
5264adaa114Sdlg }
5274adaa114Sdlg
5283a2eabfeSkettenis void
print_pcie_ls(uint8_t speed)52958cbacc3Sjsg print_pcie_ls(uint8_t speed)
53058cbacc3Sjsg {
53154f9e571Skettenis if (speed == 6)
53254f9e571Skettenis printf("64.0");
53354f9e571Skettenis else if (speed == 5)
53454f9e571Skettenis printf("32.0");
53554f9e571Skettenis else if (speed == 4)
53654f9e571Skettenis printf("16.0");
53754f9e571Skettenis else if (speed == 3)
538d5fc1bc8Sjsg printf("8.0");
53954f9e571Skettenis else if (speed == 2)
540e1b2e8d4Sjsg printf("5.0");
54154f9e571Skettenis else if (speed == 1)
542e1b2e8d4Sjsg printf("2.5");
543e1b2e8d4Sjsg else
54458cbacc3Sjsg printf("unknown (%d)", speed);
54558cbacc3Sjsg }
54658cbacc3Sjsg
54758cbacc3Sjsg void
dump_pcie_linkspeed(int bus,int dev,int func,uint8_t ptr)54858cbacc3Sjsg dump_pcie_linkspeed(int bus, int dev, int func, uint8_t ptr)
54958cbacc3Sjsg {
5504adaa114Sdlg u_int32_t dcap, dcsr;
55154f9e571Skettenis u_int32_t lcap, lcsr;
552311a3a94Sderaadt u_int8_t cwidth, cspeed, swidth, sspeed;
55358cbacc3Sjsg
5544adaa114Sdlg if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCAP, &dcap) != 0)
5554adaa114Sdlg return;
5564adaa114Sdlg
5574adaa114Sdlg if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCSR, &dcsr) != 0)
5584adaa114Sdlg return;
5594adaa114Sdlg
5604adaa114Sdlg printf("\t\tMax Payload Size: %u / %u bytes\n",
5614adaa114Sdlg pcie_dcsr_mps(dcsr), pcie_dcap_mps(dcap));
5624adaa114Sdlg printf("\t\tMax Read Request Size: %u bytes\n",
5634adaa114Sdlg pcie_dcsr_mrrs(dcsr));
5644adaa114Sdlg
565e1b2e8d4Sjsg if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP, &lcap) != 0)
566e1b2e8d4Sjsg return;
567e1b2e8d4Sjsg cspeed = lcap & 0x0f;
568e1b2e8d4Sjsg cwidth = (lcap >> 4) & 0x3f;
56958cbacc3Sjsg if (cwidth == 0)
57058cbacc3Sjsg return;
57158cbacc3Sjsg
57254f9e571Skettenis if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCSR, &lcsr) != 0)
57354f9e571Skettenis return;
57454f9e571Skettenis sspeed = (lcsr >> 16) & 0x0f;
57554f9e571Skettenis swidth = (lcsr >> 20) & 0x3f;
576e1b2e8d4Sjsg
577262d46aaSdlg printf("\t\tLink Speed: ");
57858cbacc3Sjsg print_pcie_ls(sspeed);
57958cbacc3Sjsg printf(" / ");
58058cbacc3Sjsg print_pcie_ls(cspeed);
5814adaa114Sdlg printf(" GT/s\n");
58258cbacc3Sjsg
5834adaa114Sdlg printf("\t\tLink Width: x%d / x%d\n", swidth, cwidth);
58458cbacc3Sjsg }
58558cbacc3Sjsg
58658cbacc3Sjsg void
dump_pcie_devserial(int bus,int dev,int func,u_int16_t ptr)5871f43da81Sdlg dump_pcie_devserial(int bus, int dev, int func, u_int16_t ptr)
5881f43da81Sdlg {
5891f43da81Sdlg uint32_t lower, upper;
5901f43da81Sdlg uint64_t serial;
5911f43da81Sdlg
5921f43da81Sdlg if ((pci_read(bus, dev, func, ptr + 8, &upper) != 0) ||
5931f43da81Sdlg (pci_read(bus, dev, func, ptr + 4, &lower) != 0))
5941f43da81Sdlg return;
5951f43da81Sdlg
5961f43da81Sdlg serial = ((uint64_t)upper << 32) | (uint64_t)lower;
5971f43da81Sdlg
5981f43da81Sdlg printf("\t\tSerial Number: %016llx\n", serial);
5991f43da81Sdlg }
6001f43da81Sdlg
6011f43da81Sdlg void
dump_msi(int bus,int dev,int func,u_int8_t ptr)602dda8f56eSjmatthew dump_msi(int bus, int dev, int func, u_int8_t ptr)
603dda8f56eSjmatthew {
604dda8f56eSjmatthew u_int32_t reg;
605dda8f56eSjmatthew
606dda8f56eSjmatthew if (pci_read(bus, dev, func, ptr, ®) != 0)
607dda8f56eSjmatthew return;
608dda8f56eSjmatthew
6093f533fe1Skettenis printf("\t\tEnabled: %s; %d vectors (%d enabled)\n",
6103f533fe1Skettenis reg & PCI_MSI_MC_MSIE ? "yes" : "no",
6113f533fe1Skettenis (1 << ((reg & PCI_MSI_MC_MMC_MASK) >> PCI_MSI_MC_MMC_SHIFT)),
6123f533fe1Skettenis (1 << ((reg & PCI_MSI_MC_MME_MASK) >> PCI_MSI_MC_MME_SHIFT)));
613dda8f56eSjmatthew }
614dda8f56eSjmatthew
615dda8f56eSjmatthew void
dump_msix(int bus,int dev,int func,u_int8_t ptr)616dda8f56eSjmatthew dump_msix(int bus, int dev, int func, u_int8_t ptr)
617dda8f56eSjmatthew {
618dda8f56eSjmatthew u_int32_t reg;
619dda8f56eSjmatthew u_int32_t table;
620dda8f56eSjmatthew
621dda8f56eSjmatthew if ((pci_read(bus, dev, func, ptr, ®) != 0) ||
622dda8f56eSjmatthew (pci_read(bus, dev, func, ptr + PCI_MSIX_TABLE, &table) != 0))
623dda8f56eSjmatthew return;
624dda8f56eSjmatthew
625dda8f56eSjmatthew printf("\t\tEnabled: %s; table size %d (BAR %d:%d)\n",
626dda8f56eSjmatthew reg & PCI_MSIX_MC_MSIXE ? "yes" : "no",
627dda8f56eSjmatthew PCI_MSIX_MC_TBLSZ(reg) + 1,
628dda8f56eSjmatthew (table & PCI_MSIX_TABLE_BIR),
629dda8f56eSjmatthew (table & PCI_MSIX_TABLE_OFF));
630dda8f56eSjmatthew }
631dda8f56eSjmatthew
632dda8f56eSjmatthew void
dump_pcie_enhanced_caplist(int bus,int dev,int func)633f9804a94Sderaadt dump_pcie_enhanced_caplist(int bus, int dev, int func)
634f9804a94Sderaadt {
635f9804a94Sderaadt u_int32_t reg;
6368e37be76Smlarkin u_int32_t capidx;
637f9804a94Sderaadt u_int16_t ptr;
638f9804a94Sderaadt u_int16_t ecap;
639f9804a94Sderaadt
640f9804a94Sderaadt ptr = PCI_PCIE_ECAP;
641f9804a94Sderaadt
642f9804a94Sderaadt do {
643f9804a94Sderaadt if (pci_read(bus, dev, func, ptr, ®) != 0)
644f9804a94Sderaadt return;
645f9804a94Sderaadt
646f9804a94Sderaadt if (PCI_PCIE_ECAP_ID(reg) == 0xffff &&
647f9804a94Sderaadt PCI_PCIE_ECAP_NEXT(reg) == PCI_PCIE_ECAP_LAST)
648f9804a94Sderaadt return;
649f9804a94Sderaadt
650f9804a94Sderaadt ecap = PCI_PCIE_ECAP_ID(reg);
651f9804a94Sderaadt if (ecap >= nitems(pci_enhanced_capnames))
6528e37be76Smlarkin capidx = 0;
6538e37be76Smlarkin else
6548e37be76Smlarkin capidx = ecap;
655f9804a94Sderaadt
656f9804a94Sderaadt printf("\t0x%04x: Enhanced Capability 0x%02x: ", ptr, ecap);
6578e37be76Smlarkin printf("%s\n", pci_enhanced_capnames[capidx]);
658f9804a94Sderaadt
6591f43da81Sdlg switch (ecap) {
6601f43da81Sdlg case 0x03:
6611f43da81Sdlg dump_pcie_devserial(bus, dev, func, ptr);
6621f43da81Sdlg break;
6631f43da81Sdlg }
6641f43da81Sdlg
665f9804a94Sderaadt ptr = PCI_PCIE_ECAP_NEXT(reg);
666f9804a94Sderaadt
667f9804a94Sderaadt } while (ptr != PCI_PCIE_ECAP_LAST);
668f9804a94Sderaadt }
669f9804a94Sderaadt
670f9804a94Sderaadt void
dump_caplist(int bus,int dev,int func,u_int8_t ptr)671b54d2ef8Sreyk dump_caplist(int bus, int dev, int func, u_int8_t ptr)
672b54d2ef8Sreyk {
673b54d2ef8Sreyk u_int32_t reg;
674b54d2ef8Sreyk u_int8_t cap;
675b54d2ef8Sreyk
676b54d2ef8Sreyk if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, ®) != 0)
677b54d2ef8Sreyk return;
678b54d2ef8Sreyk if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
679b54d2ef8Sreyk return;
680b54d2ef8Sreyk
681b54d2ef8Sreyk if (pci_read(bus, dev, func, ptr, ®) != 0)
682b54d2ef8Sreyk return;
683b54d2ef8Sreyk ptr = PCI_CAPLIST_PTR(reg);
684b54d2ef8Sreyk while (ptr != 0) {
685b54d2ef8Sreyk if (pci_read(bus, dev, func, ptr, ®) != 0)
686b54d2ef8Sreyk return;
687b54d2ef8Sreyk cap = PCI_CAPLIST_CAP(reg);
688b54d2ef8Sreyk printf("\t0x%04x: Capability 0x%02x: ", ptr, cap);
6896bdb5af8Sjsg if (cap >= nitems(pci_capnames))
690b54d2ef8Sreyk cap = 0;
691b54d2ef8Sreyk printf("%s\n", pci_capnames[cap]);
692374253acSdlg switch (cap) {
693374253acSdlg case PCI_CAP_PWRMGMT:
6943a2eabfeSkettenis dump_pci_powerstate(bus, dev, func, ptr);
695374253acSdlg break;
6964b96984bSdlg case PCI_CAP_VPD:
6974b96984bSdlg dump_vpd(bus, dev, func);
6984b96984bSdlg break;
699374253acSdlg case PCI_CAP_PCIEXPRESS:
70058cbacc3Sjsg dump_pcie_linkspeed(bus, dev, func, ptr);
701f9804a94Sderaadt dump_pcie_enhanced_caplist(bus, dev, func);
702374253acSdlg break;
703dda8f56eSjmatthew case PCI_CAP_MSI:
704dda8f56eSjmatthew dump_msi(bus, dev,func, ptr);
705dda8f56eSjmatthew break;
706dda8f56eSjmatthew case PCI_CAP_MSIX:
707dda8f56eSjmatthew dump_msix(bus, dev, func, ptr);
708dda8f56eSjmatthew break;
709f9804a94Sderaadt }
710b54d2ef8Sreyk ptr = PCI_CAPLIST_NEXT(reg);
711b54d2ef8Sreyk }
712b54d2ef8Sreyk }
713b54d2ef8Sreyk
714b54d2ef8Sreyk void
dump_bars(int bus,int dev,int func,int end)7154719bcb4Skettenis dump_bars(int bus, int dev, int func, int end)
7167551f766Skettenis {
717604e6abeSdlg const char *memtype;
718604e6abeSdlg u_int64_t mem;
719d01993f3Skettenis u_int64_t mask;
720d01993f3Skettenis u_int32_t reg, reg1;
7217551f766Skettenis int bar;
7227551f766Skettenis
7234719bcb4Skettenis for (bar = PCI_MAPREG_START; bar < end; bar += 0x4) {
724d01993f3Skettenis if (pci_read(bus, dev, func, bar, ®) != 0 ||
725d01993f3Skettenis pci_readmask(bus, dev, func, bar, ®1) != 0)
7267551f766Skettenis warn("unable to read PCI_MAPREG 0x%02x", bar);
727604e6abeSdlg
728604e6abeSdlg printf("\t0x%04x: BAR ", bar);
729604e6abeSdlg
730d01993f3Skettenis if (reg == 0 && reg1 == 0) {
731604e6abeSdlg printf("empty (%08x)\n", reg);
732604e6abeSdlg continue;
733604e6abeSdlg }
734604e6abeSdlg
735604e6abeSdlg switch (PCI_MAPREG_TYPE(reg)) {
736604e6abeSdlg case PCI_MAPREG_TYPE_MEM:
737604e6abeSdlg printf("mem ");
738604e6abeSdlg if (PCI_MAPREG_MEM_PREFETCHABLE(reg))
739604e6abeSdlg printf("prefetchable ");
740604e6abeSdlg
741604e6abeSdlg memtype = "32bit 1m";
742604e6abeSdlg switch (PCI_MAPREG_MEM_TYPE(reg)) {
743604e6abeSdlg case PCI_MAPREG_MEM_TYPE_32BIT:
744604e6abeSdlg memtype = "32bit";
745604e6abeSdlg case PCI_MAPREG_MEM_TYPE_32BIT_1M:
746604e6abeSdlg printf("%s ", memtype);
747604e6abeSdlg
748d01993f3Skettenis printf("addr: 0x%08x/0x%08x\n",
749d01993f3Skettenis PCI_MAPREG_MEM_ADDR(reg),
750d01993f3Skettenis PCI_MAPREG_MEM_SIZE(reg1));
751604e6abeSdlg
752604e6abeSdlg break;
753604e6abeSdlg case PCI_MAPREG_MEM_TYPE_64BIT:
754604e6abeSdlg mem = reg;
755d01993f3Skettenis mask = reg1;
756604e6abeSdlg bar += 0x04;
757d01993f3Skettenis if (pci_read(bus, dev, func, bar, ®) != 0 ||
758d01993f3Skettenis pci_readmask(bus, dev, func, bar, ®1) != 0)
759604e6abeSdlg warn("unable to read 0x%02x", bar);
760604e6abeSdlg
761604e6abeSdlg mem |= (u_int64_t)reg << 32;
762d01993f3Skettenis mask |= (u_int64_t)reg1 << 32;
763604e6abeSdlg
764d01993f3Skettenis printf("64bit addr: 0x%016llx/0x%08llx\n",
765d01993f3Skettenis PCI_MAPREG_MEM64_ADDR(mem),
766d01993f3Skettenis PCI_MAPREG_MEM64_SIZE(mask));
767604e6abeSdlg
768604e6abeSdlg break;
769604e6abeSdlg }
770604e6abeSdlg break;
771604e6abeSdlg
772604e6abeSdlg case PCI_MAPREG_TYPE_IO:
773d01993f3Skettenis printf("io addr: 0x%08x/0x%04x\n",
774d01993f3Skettenis PCI_MAPREG_IO_ADDR(reg),
775d01993f3Skettenis PCI_MAPREG_IO_SIZE(reg1));
776604e6abeSdlg break;
777604e6abeSdlg }
7787551f766Skettenis }
7794719bcb4Skettenis }
7804719bcb4Skettenis
7814719bcb4Skettenis void
dump_type0(int bus,int dev,int func)7824719bcb4Skettenis dump_type0(int bus, int dev, int func)
7834719bcb4Skettenis {
7844719bcb4Skettenis u_int32_t reg;
7854719bcb4Skettenis
7864719bcb4Skettenis dump_bars(bus, dev, func, PCI_MAPREG_END);
7877551f766Skettenis
7887551f766Skettenis if (pci_read(bus, dev, func, PCI_CARDBUS_CIS_REG, ®) != 0)
7897551f766Skettenis warn("unable to read PCI_CARDBUS_CIS_REG");
7907551f766Skettenis printf("\t0x%04x: Cardbus CIS: %08x\n", PCI_CARDBUS_CIS_REG, reg);
7917551f766Skettenis
7927551f766Skettenis if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG, ®) != 0)
7937551f766Skettenis warn("unable to read PCI_SUBSYS_ID_REG");
7947551f766Skettenis printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
7957551f766Skettenis PCI_SUBSYS_ID_REG, PCI_VENDOR(reg), PCI_PRODUCT(reg));
7967551f766Skettenis
7977551f766Skettenis if (pci_read(bus, dev, func, PCI_ROM_REG, ®) != 0)
7987551f766Skettenis warn("unable to read PCI_ROM_REG");
7997551f766Skettenis printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
8007551f766Skettenis PCI_ROM_REG, reg);
8017551f766Skettenis
8027551f766Skettenis if (pci_read(bus, dev, func, 0x38, ®) != 0)
8037551f766Skettenis warn("unable to read 0x38 (reserved)");
8047551f766Skettenis printf("\t0x%04x: %08x\n", 0x38, reg);
8057551f766Skettenis
8067551f766Skettenis if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
8077551f766Skettenis warn("unable to read PCI_INTERRUPT_REG");
8087551f766Skettenis printf("\t0x%04x: Interrupt Pin: %02x Line: %02x Min Gnt: %02x"
8097551f766Skettenis " Max Lat: %02x\n", PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
8107551f766Skettenis PCI_INTERRUPT_LINE(reg), PCI_MIN_GNT(reg), PCI_MAX_LAT(reg));
8117551f766Skettenis }
8127551f766Skettenis
8137551f766Skettenis void
dump_type1(int bus,int dev,int func)8147551f766Skettenis dump_type1(int bus, int dev, int func)
8157551f766Skettenis {
8167551f766Skettenis u_int32_t reg;
8177551f766Skettenis
8184719bcb4Skettenis dump_bars(bus, dev, func, PCI_MAPREG_PPB_END);
8197551f766Skettenis
8207551f766Skettenis if (pci_read(bus, dev, func, PCI_PRIBUS_1, ®) != 0)
8217551f766Skettenis warn("unable to read PCI_PRIBUS_1");
822262d46aaSdlg printf("\t0x%04x: Primary Bus: %d, Secondary Bus: %d, "
823262d46aaSdlg "Subordinate Bus: %d,\n\t\tSecondary Latency Timer: %02x\n",
8247551f766Skettenis PCI_PRIBUS_1, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
8257551f766Skettenis (reg >> 16) & 0xff, (reg >> 24) & 0xff);
8267551f766Skettenis
8277551f766Skettenis if (pci_read(bus, dev, func, PCI_IOBASEL_1, ®) != 0)
8287551f766Skettenis warn("unable to read PCI_IOBASEL_1");
829262d46aaSdlg printf("\t0x%04x: I/O Base: %02x, I/O Limit: %02x, "
8307551f766Skettenis "Secondary Status: %04x\n", PCI_IOBASEL_1, (reg >> 0 ) & 0xff,
8317551f766Skettenis (reg >> 8) & 0xff, (reg >> 16) & 0xffff);
8327551f766Skettenis
8337551f766Skettenis if (pci_read(bus, dev, func, PCI_MEMBASE_1, ®) != 0)
8347551f766Skettenis warn("unable to read PCI_MEMBASE_1");
835262d46aaSdlg printf("\t0x%04x: Memory Base: %04x, Memory Limit: %04x\n",
8367551f766Skettenis PCI_MEMBASE_1, (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
8377551f766Skettenis
8387551f766Skettenis if (pci_read(bus, dev, func, PCI_PMBASEL_1, ®) != 0)
8397551f766Skettenis warn("unable to read PCI_PMBASEL_1");
840262d46aaSdlg printf("\t0x%04x: Prefetch Memory Base: %04x, "
8417551f766Skettenis "Prefetch Memory Limit: %04x\n", PCI_PMBASEL_1,
8427551f766Skettenis (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
8437551f766Skettenis
8447551f766Skettenis #undef PCI_PMBASEH_1
8457551f766Skettenis #define PCI_PMBASEH_1 0x28
8467551f766Skettenis if (pci_read(bus, dev, func, PCI_PMBASEH_1, ®) != 0)
8477551f766Skettenis warn("unable to read PCI_PMBASEH_1");
8487551f766Skettenis printf("\t0x%04x: Prefetch Memory Base Upper 32 Bits: %08x\n",
8497551f766Skettenis PCI_PMBASEH_1, reg);
8507551f766Skettenis
8517551f766Skettenis #undef PCI_PMLIMITH_1
8527551f766Skettenis #define PCI_PMLIMITH_1 0x2c
8537551f766Skettenis if (pci_read(bus, dev, func, PCI_PMLIMITH_1, ®) != 0)
8547551f766Skettenis warn("unable to read PCI_PMLIMITH_1");
8557551f766Skettenis printf("\t0x%04x: Prefetch Memory Limit Upper 32 Bits: %08x\n",
8567551f766Skettenis PCI_PMLIMITH_1, reg);
8577551f766Skettenis
8587551f766Skettenis #undef PCI_IOBASEH_1
8597551f766Skettenis #define PCI_IOBASEH_1 0x30
8607551f766Skettenis if (pci_read(bus, dev, func, PCI_IOBASEH_1, ®) != 0)
8617551f766Skettenis warn("unable to read PCI_IOBASEH_1");
862262d46aaSdlg printf("\t0x%04x: I/O Base Upper 16 Bits: %04x, "
8637551f766Skettenis "I/O Limit Upper 16 Bits: %04x\n", PCI_IOBASEH_1,
8647551f766Skettenis (reg >> 0) & 0xffff, (reg >> 16) & 0xffff);
8657551f766Skettenis
8667551f766Skettenis #define PCI_PPB_ROM_REG 0x38
8677551f766Skettenis if (pci_read(bus, dev, func, PCI_PPB_ROM_REG, ®) != 0)
8687551f766Skettenis warn("unable to read PCI_PPB_ROM_REG");
8697551f766Skettenis printf("\t0x%04x: Expansion ROM Base Address: %08x\n",
8707551f766Skettenis PCI_PPB_ROM_REG, reg);
8717551f766Skettenis
8727551f766Skettenis if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
8737551f766Skettenis warn("unable to read PCI_INTERRUPT_REG");
874262d46aaSdlg printf("\t0x%04x: Interrupt Pin: %02x, Line: %02x, "
8757551f766Skettenis "Bridge Control: %04x\n",
8767551f766Skettenis PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
8777551f766Skettenis PCI_INTERRUPT_LINE(reg), reg >> 16);
8787551f766Skettenis }
8797551f766Skettenis
8807551f766Skettenis void
dump_type2(int bus,int dev,int func)8817551f766Skettenis dump_type2(int bus, int dev, int func)
8827551f766Skettenis {
8837551f766Skettenis u_int32_t reg;
8847551f766Skettenis
8857551f766Skettenis if (pci_read(bus, dev, func, PCI_MAPREG_START, ®) != 0)
8867551f766Skettenis warn("unable to read PCI_MAPREG\n");
8877551f766Skettenis printf("\t0x%04x: Cardbus Control Registers Base Address: %08x\n",
8887551f766Skettenis PCI_MAPREG_START, reg);
8897551f766Skettenis
8907551f766Skettenis if (pci_read(bus, dev, func, PCI_PRIBUS_2, ®) != 0)
8917551f766Skettenis warn("unable to read PCI_PRIBUS_2");
8927551f766Skettenis printf("\t0x%04x: Primary Bus: %d Cardbus Bus: %d "
8937551f766Skettenis "Subordinate Bus: %d \n\t Cardbus Latency Timer: %02x\n",
8947551f766Skettenis PCI_PRIBUS_2, (reg >> 0) & 0xff, (reg >> 8) & 0xff,
8957551f766Skettenis (reg >> 16) & 0xff, (reg >> 24) & 0xff);
8967551f766Skettenis
8977551f766Skettenis if (pci_read(bus, dev, func, PCI_MEMBASE0_2, ®) != 0)
8987551f766Skettenis warn("unable to read PCI_MEMBASE0_2\n");
8997551f766Skettenis printf("\t0x%04x: Memory Base 0: %08x\n", PCI_MEMBASE0_2, reg);
9007551f766Skettenis
9017551f766Skettenis if (pci_read(bus, dev, func, PCI_MEMLIMIT0_2, ®) != 0)
9027551f766Skettenis warn("unable to read PCI_MEMLIMIT0_2\n");
9037551f766Skettenis printf("\t0x%04x: Memory Limit 0: %08x\n", PCI_MEMLIMIT0_2, reg);
9047551f766Skettenis
9057551f766Skettenis if (pci_read(bus, dev, func, PCI_MEMBASE1_2, ®) != 0)
9067551f766Skettenis warn("unable to read PCI_MEMBASE1_2\n");
9077551f766Skettenis printf("\t0x%04x: Memory Base 1: %08x\n", PCI_MEMBASE1_2, reg);
9087551f766Skettenis
9097551f766Skettenis if (pci_read(bus, dev, func, PCI_MEMLIMIT1_2, ®) != 0)
9107551f766Skettenis warn("unable to read PCI_MEMLIMIT1_2\n");
9117551f766Skettenis printf("\t0x%04x: Memory Limit 1: %08x\n", PCI_MEMLIMIT1_2, reg);
9127551f766Skettenis
9137551f766Skettenis if (pci_read(bus, dev, func, PCI_IOBASE0_2, ®) != 0)
9147551f766Skettenis warn("unable to read PCI_IOBASE0_2\n");
9157551f766Skettenis printf("\t0x%04x: I/O Base 0: %08x\n", PCI_IOBASE0_2, reg);
9167551f766Skettenis
9177551f766Skettenis if (pci_read(bus, dev, func, PCI_IOLIMIT0_2, ®) != 0)
9187551f766Skettenis warn("unable to read PCI_IOLIMIT0_2\n");
9197551f766Skettenis printf("\t0x%04x: I/O Limit 0: %08x\n", PCI_IOLIMIT0_2, reg);
9207551f766Skettenis
9217551f766Skettenis if (pci_read(bus, dev, func, PCI_IOBASE1_2, ®) != 0)
9227551f766Skettenis warn("unable to read PCI_IOBASE1_2\n");
9237551f766Skettenis printf("\t0x%04x: I/O Base 1: %08x\n", PCI_IOBASE1_2, reg);
9247551f766Skettenis
9257551f766Skettenis if (pci_read(bus, dev, func, PCI_IOLIMIT1_2, ®) != 0)
9267551f766Skettenis warn("unable to read PCI_IOLIMIT1_2\n");
9277551f766Skettenis printf("\t0x%04x: I/O Limit 1: %08x\n", PCI_IOLIMIT1_2, reg);
9287551f766Skettenis
9297551f766Skettenis if (pci_read(bus, dev, func, PCI_INTERRUPT_REG, ®) != 0)
9307551f766Skettenis warn("unable to read PCI_INTERRUPT_REG");
9317551f766Skettenis printf("\t0x%04x: Interrupt Pin: %02x Line: %02x "
9327551f766Skettenis "Bridge Control: %04x\n",
9337551f766Skettenis PCI_INTERRUPT_REG, PCI_INTERRUPT_PIN(reg),
9347551f766Skettenis PCI_INTERRUPT_LINE(reg), reg >> 16);
9357551f766Skettenis
9367551f766Skettenis if (pci_read(bus, dev, func, PCI_SUBVEND_2, ®) != 0)
9377551f766Skettenis warn("unable to read PCI_SUBVEND_2");
9387551f766Skettenis printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n",
9397551f766Skettenis PCI_SUBVEND_2, PCI_VENDOR(reg), PCI_PRODUCT(reg));
9407551f766Skettenis
9417551f766Skettenis if (pci_read(bus, dev, func, PCI_PCCARDIF_2, ®) != 0)
9427551f766Skettenis warn("unable to read PCI_PCCARDIF_2\n");
9437551f766Skettenis printf("\t0x%04x: 16-bit Legacy Mode Base Address: %08x\n",
9447551f766Skettenis PCI_PCCARDIF_2, reg);
9457551f766Skettenis }
9467551f766Skettenis
9477551f766Skettenis void
dump(int bus,int dev,int func)9481f680598Sdlg dump(int bus, int dev, int func)
9491f680598Sdlg {
9501f680598Sdlg u_int32_t reg;
951b54d2ef8Sreyk u_int8_t capptr = PCI_CAPLISTPTR_REG;
95206b03c88Sdlg pci_class_t class;
95306b03c88Sdlg pci_subclass_t subclass;
9541f680598Sdlg
9551f680598Sdlg if (pci_read(bus, dev, func, PCI_ID_REG, ®) != 0)
9561f680598Sdlg warn("unable to read PCI_ID_REG");
957262d46aaSdlg printf("\t0x%04x: Vendor ID: %04x, Product ID: %04x\n", PCI_ID_REG,
9581f680598Sdlg PCI_VENDOR(reg), PCI_PRODUCT(reg));
9591f680598Sdlg
9601f680598Sdlg if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG, ®) != 0)
9611f680598Sdlg warn("unable to read PCI_COMMAND_STATUS_REG");
962262d46aaSdlg printf("\t0x%04x: Command: %04x, Status: %04x\n",
9631f680598Sdlg PCI_COMMAND_STATUS_REG, reg & 0xffff, (reg >> 16) & 0xffff);
9641f680598Sdlg
9651f680598Sdlg if (pci_read(bus, dev, func, PCI_CLASS_REG, ®) != 0)
9661f680598Sdlg warn("unable to read PCI_CLASS_REG");
96706b03c88Sdlg class = PCI_CLASS(reg);
96806b03c88Sdlg subclass = PCI_SUBCLASS(reg);
969262d46aaSdlg printf("\t0x%04x:\tClass: %02x %s,", PCI_CLASS_REG, class,
97006b03c88Sdlg pci_class_name(class));
971262d46aaSdlg printf(" Subclass: %02x %s,", subclass,
97206b03c88Sdlg pci_subclass_name(class, subclass));
973262d46aaSdlg printf("\n\t\tInterface: %02x, Revision: %02x\n",
97406b03c88Sdlg PCI_INTERFACE(reg), PCI_REVISION(reg));
9751f680598Sdlg
9761f680598Sdlg if (pci_read(bus, dev, func, PCI_BHLC_REG, ®) != 0)
9771f680598Sdlg warn("unable to read PCI_BHLC_REG");
978262d46aaSdlg printf("\t0x%04x: BIST: %02x, Header Type: %02x, "
979262d46aaSdlg "Latency Timer: %02x,\n\t\tCache Line Size: %02x\n", PCI_BHLC_REG,
980262d46aaSdlg PCI_BIST(reg), PCI_HDRTYPE(reg),
981262d46aaSdlg PCI_LATTIMER(reg), PCI_CACHELINE(reg));
9821f680598Sdlg
9837551f766Skettenis switch (PCI_HDRTYPE_TYPE(reg)) {
9847551f766Skettenis case 2:
9857551f766Skettenis dump_type2(bus, dev, func);
986b54d2ef8Sreyk capptr = PCI_CARDBUS_CAPLISTPTR_REG;
9877551f766Skettenis break;
9887551f766Skettenis case 1:
9897551f766Skettenis dump_type1(bus, dev, func);
9907551f766Skettenis break;
9917551f766Skettenis case 0:
9927551f766Skettenis dump_type0(bus, dev, func);
9937551f766Skettenis break;
9947551f766Skettenis default:
9957551f766Skettenis break;
9961f680598Sdlg }
997b54d2ef8Sreyk dump_caplist(bus, dev, func, capptr);
9981f680598Sdlg }
9991f680598Sdlg
10006e862d19Skettenis void
hexdump(int bus,int dev,int func,int size)10015d2ed882Skettenis hexdump(int bus, int dev, int func, int size)
10026e862d19Skettenis {
10036e862d19Skettenis u_int32_t reg;
10046e862d19Skettenis int i;
10056e862d19Skettenis
10065d2ed882Skettenis for (i = 0; i < size; i += 4) {
10075d2ed882Skettenis if (pci_read(bus, dev, func, i, ®) != 0) {
10085d2ed882Skettenis if (errno == EINVAL)
10095d2ed882Skettenis return;
10105d2ed882Skettenis warn("unable to read 0x%02x", i);
10115d2ed882Skettenis }
10125d2ed882Skettenis
10136e862d19Skettenis if ((i % 16) == 0)
10146e862d19Skettenis printf("\t0x%04x:", i);
10156e862d19Skettenis printf(" %08x", reg);
10166e862d19Skettenis
10176e862d19Skettenis if ((i % 16) == 12)
10186e862d19Skettenis printf("\n");
10196e862d19Skettenis }
10206e862d19Skettenis }
10216e862d19Skettenis
10221f680598Sdlg int
pci_nfuncs(int bus,int dev)10231f680598Sdlg pci_nfuncs(int bus, int dev)
10241f680598Sdlg {
10251f680598Sdlg u_int32_t hdr;
10261f680598Sdlg
10271f680598Sdlg if (pci_read(bus, dev, 0, PCI_BHLC_REG, &hdr) != 0)
10281f680598Sdlg return (-1);
10291f680598Sdlg
10301f680598Sdlg return (PCI_HDRTYPE_MULTIFN(hdr) ? 8 : 1);
10311f680598Sdlg }
10321f680598Sdlg
10331f680598Sdlg int
pci_read(int bus,int dev,int func,u_int32_t reg,u_int32_t * val)10341f680598Sdlg pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
10351f680598Sdlg {
10361f680598Sdlg struct pci_io io;
10371f680598Sdlg int rv;
10381f680598Sdlg
10391f680598Sdlg bzero(&io, sizeof(io));
10401f680598Sdlg io.pi_sel.pc_bus = bus;
10411f680598Sdlg io.pi_sel.pc_dev = dev;
10421f680598Sdlg io.pi_sel.pc_func = func;
10431f680598Sdlg io.pi_reg = reg;
10441f680598Sdlg io.pi_width = 4;
10451f680598Sdlg
10461f680598Sdlg rv = ioctl(pcifd, PCIOCREAD, &io);
10471f680598Sdlg if (rv != 0)
10481f680598Sdlg return (rv);
10491f680598Sdlg
10501f680598Sdlg *val = io.pi_data;
10511f680598Sdlg
10521f680598Sdlg return (0);
10531f680598Sdlg }
10542c15f759Skettenis
10552c15f759Skettenis int
pci_readmask(int bus,int dev,int func,u_int32_t reg,u_int32_t * val)1056d01993f3Skettenis pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val)
1057d01993f3Skettenis {
1058d01993f3Skettenis struct pci_io io;
1059d01993f3Skettenis int rv;
1060d01993f3Skettenis
1061d01993f3Skettenis bzero(&io, sizeof(io));
1062d01993f3Skettenis io.pi_sel.pc_bus = bus;
1063d01993f3Skettenis io.pi_sel.pc_dev = dev;
1064d01993f3Skettenis io.pi_sel.pc_func = func;
1065d01993f3Skettenis io.pi_reg = reg;
1066d01993f3Skettenis io.pi_width = 4;
1067d01993f3Skettenis
1068d01993f3Skettenis rv = ioctl(pcifd, PCIOCREADMASK, &io);
1069d01993f3Skettenis if (rv != 0)
1070d01993f3Skettenis return (rv);
1071d01993f3Skettenis
1072d01993f3Skettenis *val = io.pi_data;
1073d01993f3Skettenis
1074d01993f3Skettenis return (0);
1075d01993f3Skettenis }
1076d01993f3Skettenis
1077d01993f3Skettenis int
dump_rom(int bus,int dev,int func)10782c15f759Skettenis dump_rom(int bus, int dev, int func)
10792c15f759Skettenis {
10802c15f759Skettenis struct pci_rom rom;
10818b86f50eSkettenis u_int32_t cr, addr;
10828b86f50eSkettenis
10838b86f50eSkettenis if (pci_read(bus, dev, func, PCI_ROM_REG, &addr) != 0 ||
10848b86f50eSkettenis pci_read(bus, dev, func, PCI_CLASS_REG, &cr) != 0)
10858b86f50eSkettenis return (errno);
10868b86f50eSkettenis
10878b86f50eSkettenis if (addr == 0 && PCI_CLASS(cr) == PCI_CLASS_DISPLAY &&
10888b86f50eSkettenis PCI_SUBCLASS(cr) == PCI_SUBCLASS_DISPLAY_VGA)
10898b86f50eSkettenis return dump_vga_bios();
10902c15f759Skettenis
10912c15f759Skettenis bzero(&rom, sizeof(rom));
10922c15f759Skettenis rom.pr_sel.pc_bus = bus;
10932c15f759Skettenis rom.pr_sel.pc_dev = dev;
10942c15f759Skettenis rom.pr_sel.pc_func = func;
1095df69c215Sderaadt if (ioctl(pcifd, PCIOCGETROMLEN, &rom) == -1)
10962c15f759Skettenis return (errno);
10972c15f759Skettenis
10982c15f759Skettenis rom.pr_rom = malloc(rom.pr_romlen);
10992c15f759Skettenis if (rom.pr_rom == NULL)
11002c15f759Skettenis return (ENOMEM);
11012c15f759Skettenis
1102df69c215Sderaadt if (ioctl(pcifd, PCIOCGETROM, &rom) == -1)
11032c15f759Skettenis return (errno);
11042c15f759Skettenis
11052c15f759Skettenis if (write(romfd, rom.pr_rom, rom.pr_romlen) == -1)
11062c15f759Skettenis return (errno);
11072c15f759Skettenis
11082c15f759Skettenis return (0);
11092c15f759Skettenis }
11108b86f50eSkettenis
11118b86f50eSkettenis #define VGA_BIOS_ADDR 0xc0000
11128b86f50eSkettenis #define VGA_BIOS_LEN 0x10000
11138b86f50eSkettenis
11148b86f50eSkettenis int
dump_vga_bios(void)11158b86f50eSkettenis dump_vga_bios(void)
11168b86f50eSkettenis {
11178b86f50eSkettenis #if defined(__amd64__) || defined(__i386__)
11188b86f50eSkettenis void *bios;
11198b86f50eSkettenis int fd;
11208b86f50eSkettenis
1121b7041c07Sderaadt fd = open(_PATH_MEM, O_RDONLY);
11228b86f50eSkettenis if (fd == -1)
11238b86f50eSkettenis err(1, "%s", _PATH_MEM);
11248b86f50eSkettenis
11258b86f50eSkettenis bios = malloc(VGA_BIOS_LEN);
11268b86f50eSkettenis if (bios == NULL)
11278b86f50eSkettenis return (ENOMEM);
11288b86f50eSkettenis
11298b86f50eSkettenis if (pread(fd, bios, VGA_BIOS_LEN, VGA_BIOS_ADDR) == -1)
11308b86f50eSkettenis err(1, "%s", _PATH_MEM);
11318b86f50eSkettenis
113248e4789bSjsg if (write(romfd, bios, VGA_BIOS_LEN) == -1) {
113348e4789bSjsg free(bios);
11348b86f50eSkettenis return (errno);
113548e4789bSjsg }
113648e4789bSjsg
113748e4789bSjsg free(bios);
11388b86f50eSkettenis
11398b86f50eSkettenis return (0);
11408b86f50eSkettenis #else
11418b86f50eSkettenis return (ENODEV);
11428b86f50eSkettenis #endif
11438b86f50eSkettenis }
114406b03c88Sdlg
114506b03c88Sdlg struct pci_subclass {
114606b03c88Sdlg pci_subclass_t subclass;
114706b03c88Sdlg const char *name;
114806b03c88Sdlg };
114906b03c88Sdlg
115006b03c88Sdlg struct pci_class {
115106b03c88Sdlg pci_class_t class;
115206b03c88Sdlg const char *name;
115306b03c88Sdlg const struct pci_subclass
115406b03c88Sdlg *subclass;
115506b03c88Sdlg size_t nsubclass;
115606b03c88Sdlg };
115706b03c88Sdlg
115806b03c88Sdlg static const struct pci_subclass pci_subclass_prehistoric[] = {
115906b03c88Sdlg { PCI_SUBCLASS_PREHISTORIC_MISC, "Miscellaneous" },
116006b03c88Sdlg { PCI_SUBCLASS_PREHISTORIC_VGA, "VGA" },
116106b03c88Sdlg };
116206b03c88Sdlg
116306b03c88Sdlg static const struct pci_subclass pci_subclass_mass_storage[] = {
116406b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_SCSI, "SCSI" },
116506b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_IDE, "IDE" },
116606b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_FLOPPY, "Floppy" },
116706b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_IPI, "IPI" },
116806b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_RAID, "RAID" },
116906b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_ATA, "ATA" },
117006b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_SATA, "SATA" },
117106b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_SAS, "SAS" },
117206b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_UFS, "UFS" },
117306b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_NVM, "NVM" },
117406b03c88Sdlg { PCI_SUBCLASS_MASS_STORAGE_MISC, "Miscellaneous" },
117506b03c88Sdlg };
117606b03c88Sdlg
117706b03c88Sdlg static const struct pci_subclass pci_subclass_network[] = {
117806b03c88Sdlg { PCI_SUBCLASS_NETWORK_ETHERNET, "Ethernet" },
117906b03c88Sdlg { PCI_SUBCLASS_NETWORK_TOKENRING, "Token Ring" },
118006b03c88Sdlg { PCI_SUBCLASS_NETWORK_FDDI, "FDDI" },
118106b03c88Sdlg { PCI_SUBCLASS_NETWORK_ATM, "ATM" },
118206b03c88Sdlg { PCI_SUBCLASS_NETWORK_ISDN, "ISDN" },
118306b03c88Sdlg { PCI_SUBCLASS_NETWORK_WORLDFIP, "WorldFip" },
118406b03c88Sdlg { PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP, "PCMIG Multi Computing" },
118506b03c88Sdlg { PCI_SUBCLASS_NETWORK_INFINIBAND, "InfiniBand" },
118606b03c88Sdlg { PCI_SUBCLASS_NETWORK_MISC, "Miscellaneous" },
118706b03c88Sdlg };
118806b03c88Sdlg
118906b03c88Sdlg static const struct pci_subclass pci_subclass_display[] = {
119006b03c88Sdlg { PCI_SUBCLASS_DISPLAY_VGA, "VGA" },
119106b03c88Sdlg { PCI_SUBCLASS_DISPLAY_XGA, "XGA" },
119206b03c88Sdlg { PCI_SUBCLASS_DISPLAY_3D, "3D" },
119306b03c88Sdlg { PCI_SUBCLASS_DISPLAY_MISC, "Miscellaneous" },
119406b03c88Sdlg };
119506b03c88Sdlg
1196fe9e6f03Sjsg static const struct pci_subclass pci_subclass_multimedia[] = {
1197fe9e6f03Sjsg { PCI_SUBCLASS_MULTIMEDIA_VIDEO, "Video" },
1198fe9e6f03Sjsg { PCI_SUBCLASS_MULTIMEDIA_AUDIO, "Audio" },
1199fe9e6f03Sjsg { PCI_SUBCLASS_MULTIMEDIA_TELEPHONY, "Telephony" },
1200fe9e6f03Sjsg { PCI_SUBCLASS_MULTIMEDIA_HDAUDIO, "HD Audio" },
1201fe9e6f03Sjsg { PCI_SUBCLASS_MULTIMEDIA_MISC, "Miscellaneous" },
1202fe9e6f03Sjsg };
1203fe9e6f03Sjsg
120406b03c88Sdlg static const struct pci_subclass pci_subclass_memory[] = {
120506b03c88Sdlg { PCI_SUBCLASS_MEMORY_RAM, "RAM" },
120606b03c88Sdlg { PCI_SUBCLASS_MEMORY_FLASH, "Flash" },
120706b03c88Sdlg { PCI_SUBCLASS_MEMORY_MISC, "Miscellaneous" },
120806b03c88Sdlg };
120906b03c88Sdlg
121006b03c88Sdlg static const struct pci_subclass pci_subclass_bridge[] = {
121106b03c88Sdlg { PCI_SUBCLASS_BRIDGE_HOST, "Host" },
121206b03c88Sdlg { PCI_SUBCLASS_BRIDGE_ISA, "ISA" },
121306b03c88Sdlg { PCI_SUBCLASS_BRIDGE_EISA, "EISA" },
121406b03c88Sdlg { PCI_SUBCLASS_BRIDGE_MC, "MicroChannel" },
121506b03c88Sdlg { PCI_SUBCLASS_BRIDGE_PCI, "PCI" },
121606b03c88Sdlg { PCI_SUBCLASS_BRIDGE_PCMCIA, "PCMCIA" },
121706b03c88Sdlg { PCI_SUBCLASS_BRIDGE_NUBUS, "NuBus" },
121806b03c88Sdlg { PCI_SUBCLASS_BRIDGE_RACEWAY, "RACEway" },
121906b03c88Sdlg { PCI_SUBCLASS_BRIDGE_STPCI, "Semi-transparent PCI" },
122006b03c88Sdlg { PCI_SUBCLASS_BRIDGE_INFINIBAND, "InfiniBand" },
122106b03c88Sdlg { PCI_SUBCLASS_BRIDGE_MISC, "Miscellaneous" },
122206b03c88Sdlg { PCI_SUBCLASS_BRIDGE_AS, "advanced switching" },
122306b03c88Sdlg };
122406b03c88Sdlg
122506b03c88Sdlg static const struct pci_subclass pci_subclass_communications[] = {
122606b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_SERIAL, "Serial" },
122706b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_PARALLEL, "Parallel" },
122806b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL, "Multi-port Serial" },
122906b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_MODEM, "Modem" },
123006b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_GPIB, "GPIB" },
123106b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD,
123206b03c88Sdlg "Smartcard" },
123306b03c88Sdlg { PCI_SUBCLASS_COMMUNICATIONS_MISC, "Miscellaneous" },
123406b03c88Sdlg };
123506b03c88Sdlg
123606b03c88Sdlg static const struct pci_subclass pci_subclass_system[] = {
123706b03c88Sdlg { PCI_SUBCLASS_SYSTEM_PIC, "Interrupt" },
123806b03c88Sdlg { PCI_SUBCLASS_SYSTEM_DMA, "8237 DMA" },
123906b03c88Sdlg { PCI_SUBCLASS_SYSTEM_TIMER, "8254 Timer" },
124006b03c88Sdlg { PCI_SUBCLASS_SYSTEM_RTC, "RTC" },
124106b03c88Sdlg { PCI_SUBCLASS_SYSTEM_SDHC, "SDHC" },
124206b03c88Sdlg { PCI_SUBCLASS_SYSTEM_IOMMU, "IOMMU" },
124306b03c88Sdlg { PCI_SUBCLASS_SYSTEM_ROOTCOMPEVENT, "Root Complex Event" },
124406b03c88Sdlg { PCI_SUBCLASS_SYSTEM_MISC, "Miscellaneous" },
124506b03c88Sdlg };
124606b03c88Sdlg
124706b03c88Sdlg static const struct pci_subclass pci_subclass_input[] = {
124806b03c88Sdlg { PCI_SUBCLASS_INPUT_KEYBOARD, "Keyboard" },
124906b03c88Sdlg { PCI_SUBCLASS_INPUT_DIGITIZER, "Digitizer" },
125006b03c88Sdlg { PCI_SUBCLASS_INPUT_MOUSE, "Mouse" },
125106b03c88Sdlg { PCI_SUBCLASS_INPUT_SCANNER, "Scanner" },
125206b03c88Sdlg { PCI_SUBCLASS_INPUT_GAMEPORT, "Game Port" },
125306b03c88Sdlg { PCI_SUBCLASS_INPUT_MISC, "Miscellaneous" },
125406b03c88Sdlg };
125506b03c88Sdlg
125606b03c88Sdlg static const struct pci_subclass pci_subclass_dock[] = {
125706b03c88Sdlg { PCI_SUBCLASS_DOCK_GENERIC, "Generic" },
125806b03c88Sdlg { PCI_SUBCLASS_DOCK_MISC, "Miscellaneous" },
125906b03c88Sdlg };
126006b03c88Sdlg
126106b03c88Sdlg static const struct pci_subclass pci_subclass_processor[] = {
126206b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_386, "386" },
126306b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_486, "486" },
126406b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_PENTIUM, "Pentium" },
126506b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_ALPHA, "Alpha" },
126606b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_POWERPC, "PowerPC" },
126706b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_MIPS, "MIPS" },
126806b03c88Sdlg { PCI_SUBCLASS_PROCESSOR_COPROC, "Co-Processor" },
126906b03c88Sdlg };
127006b03c88Sdlg
127106b03c88Sdlg static const struct pci_subclass pci_subclass_serialbus[] = {
127206b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_FIREWIRE, "FireWire" },
127306b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_ACCESS, "ACCESS.bus" },
127406b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_SSA, "SSA" },
127506b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_USB, "USB" },
127606b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_FIBER, "Fiber Channel" },
127706b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_SMBUS, "SMBus" },
127806b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_INFINIBAND, "InfiniBand" },
127906b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_IPMI, "IPMI" },
128006b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_SERCOS, "SERCOS" },
128106b03c88Sdlg { PCI_SUBCLASS_SERIALBUS_CANBUS, "CANbus" },
128206b03c88Sdlg };
128306b03c88Sdlg
128406b03c88Sdlg static const struct pci_subclass pci_subclass_wireless[] = {
128506b03c88Sdlg { PCI_SUBCLASS_WIRELESS_IRDA, "IrDA" },
128606b03c88Sdlg { PCI_SUBCLASS_WIRELESS_CONSUMERIR, "Consumer IR" },
128706b03c88Sdlg { PCI_SUBCLASS_WIRELESS_RF, "RF" },
128806b03c88Sdlg { PCI_SUBCLASS_WIRELESS_BLUETOOTH, "Bluetooth" },
128906b03c88Sdlg { PCI_SUBCLASS_WIRELESS_BROADBAND, "Broadband" },
129006b03c88Sdlg { PCI_SUBCLASS_WIRELESS_802_11A, "802.11a" },
129106b03c88Sdlg { PCI_SUBCLASS_WIRELESS_802_11B, "802.11b" },
129206b03c88Sdlg { PCI_SUBCLASS_WIRELESS_MISC, "Miscellaneous" },
129306b03c88Sdlg };
129406b03c88Sdlg
129506b03c88Sdlg static const struct pci_subclass pci_subclass_i2o[] = {
129606b03c88Sdlg { PCI_SUBCLASS_I2O_STANDARD, "Standard" },
129706b03c88Sdlg };
129806b03c88Sdlg
129906b03c88Sdlg static const struct pci_subclass pci_subclass_satcom[] = {
130006b03c88Sdlg { PCI_SUBCLASS_SATCOM_TV, "TV" },
130106b03c88Sdlg { PCI_SUBCLASS_SATCOM_AUDIO, "Audio" },
130206b03c88Sdlg { PCI_SUBCLASS_SATCOM_VOICE, "Voice" },
130306b03c88Sdlg { PCI_SUBCLASS_SATCOM_DATA, "Data" },
130406b03c88Sdlg };
130506b03c88Sdlg
130606b03c88Sdlg static const struct pci_subclass pci_subclass_crypto[] = {
130706b03c88Sdlg { PCI_SUBCLASS_CRYPTO_NETCOMP, "Network/Computing" },
130806b03c88Sdlg { PCI_SUBCLASS_CRYPTO_ENTERTAINMENT, "Entertainment" },
130906b03c88Sdlg { PCI_SUBCLASS_CRYPTO_MISC, "Miscellaneous" },
131006b03c88Sdlg };
131106b03c88Sdlg
131206b03c88Sdlg static const struct pci_subclass pci_subclass_dasp[] = {
131306b03c88Sdlg { PCI_SUBCLASS_DASP_DPIO, "DPIO" },
131406b03c88Sdlg { PCI_SUBCLASS_DASP_TIMEFREQ, "Time and Frequency" },
131506b03c88Sdlg { PCI_SUBCLASS_DASP_SYNC, "Synchronization" },
131606b03c88Sdlg { PCI_SUBCLASS_DASP_MGMT, "Management" },
131706b03c88Sdlg { PCI_SUBCLASS_DASP_MISC, "Miscellaneous" },
131806b03c88Sdlg };
131906b03c88Sdlg
13208c95b155Sjan static const struct pci_subclass pci_subclass_accelerator[] = {};
13218c95b155Sjan static const struct pci_subclass pci_subclass_instrumentation[] = {};
1322911d903bSjan
132306b03c88Sdlg #define CLASS(_c, _n, _s) { \
132406b03c88Sdlg .class = _c, \
132506b03c88Sdlg .name = _n, \
132606b03c88Sdlg .subclass = _s, \
132706b03c88Sdlg .nsubclass = nitems(_s), \
132806b03c88Sdlg }
132906b03c88Sdlg
133006b03c88Sdlg static const struct pci_class pci_classes[] = {
133106b03c88Sdlg CLASS(PCI_CLASS_PREHISTORIC, "Prehistoric",
133206b03c88Sdlg pci_subclass_prehistoric),
133306b03c88Sdlg CLASS(PCI_CLASS_MASS_STORAGE, "Mass Storage",
133406b03c88Sdlg pci_subclass_mass_storage),
133506b03c88Sdlg CLASS(PCI_CLASS_NETWORK, "Network",
133606b03c88Sdlg pci_subclass_network),
133706b03c88Sdlg CLASS(PCI_CLASS_DISPLAY, "Display",
133806b03c88Sdlg pci_subclass_display),
1339fe9e6f03Sjsg CLASS(PCI_CLASS_MULTIMEDIA, "Multimedia",
1340fe9e6f03Sjsg pci_subclass_multimedia),
134106b03c88Sdlg CLASS(PCI_CLASS_MEMORY, "Memory",
134206b03c88Sdlg pci_subclass_memory),
134306b03c88Sdlg CLASS(PCI_CLASS_BRIDGE, "Bridge",
134406b03c88Sdlg pci_subclass_bridge),
134506b03c88Sdlg CLASS(PCI_CLASS_COMMUNICATIONS, "Communications",
134606b03c88Sdlg pci_subclass_communications),
134706b03c88Sdlg CLASS(PCI_CLASS_SYSTEM, "System",
134806b03c88Sdlg pci_subclass_system),
134906b03c88Sdlg CLASS(PCI_CLASS_INPUT, "Input",
135006b03c88Sdlg pci_subclass_input),
135106b03c88Sdlg CLASS(PCI_CLASS_DOCK, "Dock",
135206b03c88Sdlg pci_subclass_dock),
135306b03c88Sdlg CLASS(PCI_CLASS_PROCESSOR, "Processor",
135406b03c88Sdlg pci_subclass_processor),
135506b03c88Sdlg CLASS(PCI_CLASS_SERIALBUS, "Serial Bus",
135606b03c88Sdlg pci_subclass_serialbus),
135706b03c88Sdlg CLASS(PCI_CLASS_WIRELESS, "Wireless",
135806b03c88Sdlg pci_subclass_wireless),
135906b03c88Sdlg CLASS(PCI_CLASS_I2O, "I2O",
136006b03c88Sdlg pci_subclass_i2o),
136106b03c88Sdlg CLASS(PCI_CLASS_SATCOM, "Satellite Comm",
136206b03c88Sdlg pci_subclass_satcom),
136306b03c88Sdlg CLASS(PCI_CLASS_CRYPTO, "Crypto",
136406b03c88Sdlg pci_subclass_crypto),
136506b03c88Sdlg CLASS(PCI_CLASS_DASP, "DASP",
136606b03c88Sdlg pci_subclass_dasp),
1367911d903bSjan CLASS(PCI_CLASS_ACCELERATOR, "Accelerator",
1368911d903bSjan pci_subclass_accelerator),
1369911d903bSjan CLASS(PCI_CLASS_INSTRUMENTATION, "Instrumentation",
1370911d903bSjan pci_subclass_instrumentation),
137106b03c88Sdlg };
137206b03c88Sdlg
137306b03c88Sdlg static const struct pci_class *
pci_class(pci_class_t class)137406b03c88Sdlg pci_class(pci_class_t class)
137506b03c88Sdlg {
137606b03c88Sdlg const struct pci_class *pc;
137706b03c88Sdlg size_t i;
137806b03c88Sdlg
137906b03c88Sdlg for (i = 0; i < nitems(pci_classes); i++) {
138006b03c88Sdlg pc = &pci_classes[i];
138106b03c88Sdlg if (pc->class == class)
138206b03c88Sdlg return (pc);
138306b03c88Sdlg }
138406b03c88Sdlg
138506b03c88Sdlg return (NULL);
138606b03c88Sdlg }
138706b03c88Sdlg
138806b03c88Sdlg static const struct pci_subclass *
pci_subclass(const struct pci_class * pc,pci_subclass_t subclass)138906b03c88Sdlg pci_subclass(const struct pci_class *pc, pci_subclass_t subclass)
139006b03c88Sdlg {
139106b03c88Sdlg const struct pci_subclass *ps;
139206b03c88Sdlg size_t i;
139306b03c88Sdlg
139406b03c88Sdlg for (i = 0; i < pc->nsubclass; i++) {
139506b03c88Sdlg ps = &pc->subclass[i];
139606b03c88Sdlg if (ps->subclass == subclass)
139706b03c88Sdlg return (ps);
139806b03c88Sdlg }
139906b03c88Sdlg
140006b03c88Sdlg return (NULL);
140106b03c88Sdlg }
140206b03c88Sdlg
140306b03c88Sdlg static const char *
pci_class_name(pci_class_t class)140406b03c88Sdlg pci_class_name(pci_class_t class)
140506b03c88Sdlg {
140606b03c88Sdlg const struct pci_class *pc;
140706b03c88Sdlg
140806b03c88Sdlg pc = pci_class(class);
140906b03c88Sdlg if (pc == NULL)
141006b03c88Sdlg return ("(unknown)");
141106b03c88Sdlg
141206b03c88Sdlg return (pc->name);
141306b03c88Sdlg }
141406b03c88Sdlg
141506b03c88Sdlg static const char *
pci_subclass_name(pci_class_t class,pci_subclass_t subclass)141606b03c88Sdlg pci_subclass_name(pci_class_t class, pci_subclass_t subclass)
141706b03c88Sdlg {
141806b03c88Sdlg const struct pci_class *pc;
141906b03c88Sdlg const struct pci_subclass *ps;
142006b03c88Sdlg
142106b03c88Sdlg pc = pci_class(class);
142206b03c88Sdlg if (pc == NULL)
142306b03c88Sdlg return ("(unknown)");
142406b03c88Sdlg
142506b03c88Sdlg ps = pci_subclass(pc, subclass);
14268c95b155Sjan if (ps == NULL || ps->name == NULL)
142706b03c88Sdlg return ("(unknown)");
142806b03c88Sdlg
142906b03c88Sdlg return (ps->name);
143006b03c88Sdlg }
1431