xref: /openbsd-src/usr.sbin/pcidump/pcidump.c (revision e6c7c102cf5d9891f32552a42895134a59937045)
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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 0)
677b54d2ef8Sreyk 		return;
678b54d2ef8Sreyk 	if (!(reg & PCI_STATUS_CAPLIST_SUPPORT))
679b54d2ef8Sreyk 		return;
680b54d2ef8Sreyk 
681b54d2ef8Sreyk 	if (pci_read(bus, dev, func, ptr, &reg) != 0)
682b54d2ef8Sreyk 		return;
683b54d2ef8Sreyk 	ptr = PCI_CAPLIST_PTR(reg);
684b54d2ef8Sreyk 	while (ptr != 0) {
685b54d2ef8Sreyk 		if (pci_read(bus, dev, func, ptr, &reg) != 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, &reg) != 0 ||
725d01993f3Skettenis 		    pci_readmask(bus, dev, func, bar, &reg1) != 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, &reg) != 0 ||
758d01993f3Skettenis 				    pci_readmask(bus, dev, func, bar, &reg1) != 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, &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, &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, &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, &reg) != 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, &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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &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, &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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &reg) != 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, &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, &reg) != 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, &reg) != 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, &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, &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, &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, &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, &reg) != 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