File: | src/usr.sbin/pcidump/pcidump.c |
Warning: | line 821, column 25 The left operand of '>>' is a garbage value |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pcidump.c,v 1.69 2023/04/16 17:26:14 kettenis Exp $ */ | |||
2 | ||||
3 | /* | |||
4 | * Copyright (c) 2006, 2007 David Gwynne <loki@animata.net> | |||
5 | * | |||
6 | * Permission to use, copy, modify, and distribute this software for any | |||
7 | * purpose with or without fee is hereby granted, provided that the above | |||
8 | * copyright notice and this permission notice appear in all copies. | |||
9 | * | |||
10 | * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES | |||
11 | * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF | |||
12 | * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR | |||
13 | * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES | |||
14 | * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN | |||
15 | * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF | |||
16 | * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. | |||
17 | */ | |||
18 | ||||
19 | #include <sys/types.h> | |||
20 | #include <sys/ioctl.h> | |||
21 | #include <sys/pciio.h> | |||
22 | ||||
23 | #include <stdio.h> /* need NULL for dev/pci/ headers */ | |||
24 | ||||
25 | #include <dev/pci/pcireg.h> | |||
26 | #include <dev/pci/pcidevs.h> | |||
27 | #include <dev/pci/pcidevs_data.h> | |||
28 | ||||
29 | #include <err.h> | |||
30 | #include <errno(*__errno()).h> | |||
31 | #include <fcntl.h> | |||
32 | #include <paths.h> | |||
33 | #include <stdlib.h> | |||
34 | #include <string.h> | |||
35 | #include <unistd.h> | |||
36 | #include <limits.h> | |||
37 | #include <vis.h> | |||
38 | ||||
39 | #define PCIDEV"/dev/pci" "/dev/pci" | |||
40 | ||||
41 | #ifndef nitems | |||
42 | #define nitems(_a)(sizeof((_a)) / sizeof((_a)[0])) (sizeof((_a)) / sizeof((_a)[0])) | |||
43 | #endif | |||
44 | ||||
45 | __dead__attribute__((__noreturn__)) void usage(void); | |||
46 | void scanpcidomain(void); | |||
47 | int probe(int, int, int); | |||
48 | void dump(int, int, int); | |||
49 | void hexdump(int, int, int, int); | |||
50 | const char *str2busdevfunc(const char *, int *, int *, int *); | |||
51 | int pci_nfuncs(int, int); | |||
52 | int pci_read(int, int, int, u_int32_t, u_int32_t *); | |||
53 | int pci_readmask(int, int, int, u_int32_t, u_int32_t *); | |||
54 | void dump_bars(int, int, int, int); | |||
55 | void dump_caplist(int, int, int, u_int8_t); | |||
56 | void dump_vpd(int, int, int); | |||
57 | void dump_pci_powerstate(int, int, int, uint8_t); | |||
58 | void dump_pcie_linkspeed(int, int, int, uint8_t); | |||
59 | void dump_pcie_devserial(int, int, int, uint16_t); | |||
60 | void dump_msi(int, int, int, uint8_t); | |||
61 | void dump_msix(int, int, int, uint8_t); | |||
62 | void print_pcie_ls(uint8_t); | |||
63 | int dump_rom(int, int, int); | |||
64 | int dump_vga_bios(void); | |||
65 | ||||
66 | static const char * | |||
67 | pci_class_name(pci_class_t); | |||
68 | static const char * | |||
69 | pci_subclass_name(pci_class_t, pci_subclass_t); | |||
70 | ||||
71 | void dump_type0(int bus, int dev, int func); | |||
72 | void dump_type1(int bus, int dev, int func); | |||
73 | void dump_type2(int bus, int dev, int func); | |||
74 | ||||
75 | __dead__attribute__((__noreturn__)) void | |||
76 | usage(void) | |||
77 | { | |||
78 | extern char *__progname; | |||
79 | ||||
80 | fprintf(stderr(&__sF[2]), | |||
81 | "usage: %s [-v] [-x | -xx | -xxx] [-d pcidev] [bus:dev:func]\n" | |||
82 | " %s -r file [-d pcidev] bus:dev:func\n", | |||
83 | __progname, __progname); | |||
84 | exit(1); | |||
85 | } | |||
86 | ||||
87 | int pcifd; | |||
88 | int romfd; | |||
89 | int verbose = 0; | |||
90 | int hex = 0; | |||
91 | int size = 64; | |||
92 | ||||
93 | const char *pci_capnames[] = { | |||
94 | "Reserved", | |||
95 | "Power Management", | |||
96 | "AGP", | |||
97 | "Vital Product Data (VPD)", | |||
98 | "Slot Identification", | |||
99 | "Message Signalled Interrupts (MSI)", | |||
100 | "CompactPCI Hot Swap", | |||
101 | "PCI-X", | |||
102 | "AMD LDT/HT", | |||
103 | "Vendor Specific", | |||
104 | "Debug Port", | |||
105 | "CompactPCI Central Resource Control", | |||
106 | "PCI Hot-Plug", | |||
107 | "PCI-PCI", | |||
108 | "AGP8", | |||
109 | "Secure", | |||
110 | "PCI Express", | |||
111 | "Extended Message Signalled Interrupts (MSI-X)", | |||
112 | "SATA", | |||
113 | "PCI Advanced Features", | |||
114 | "Enhanced Allocation", | |||
115 | "Flattening Portal Bridge", | |||
116 | }; | |||
117 | ||||
118 | const char *pci_enhanced_capnames[] = { | |||
119 | "Unknown", | |||
120 | "Advanced Error Reporting", | |||
121 | "Virtual Channel Capability", | |||
122 | "Device Serial Number", | |||
123 | "Power Budgeting", | |||
124 | "Root Complex Link Declaration", | |||
125 | "Root Complex Internal Link Control", | |||
126 | "Root Complex Event Collector", | |||
127 | "Multi-Function VC Capability", | |||
128 | "Virtual Channel Capability", | |||
129 | "Root Complex/Root Bridge", | |||
130 | "Vendor-Specific", | |||
131 | "Config Access", | |||
132 | "Access Control Services", | |||
133 | "Alternate Routing ID", | |||
134 | "Address Translation Services", | |||
135 | "Single Root I/O Virtualization", | |||
136 | "Multi Root I/O Virtualization", | |||
137 | "Multicast", | |||
138 | "Page Request Interface", | |||
139 | "Reserved for AMD", | |||
140 | "Resizable BAR", | |||
141 | "Dynamic Power Allocation", | |||
142 | "TPH Requester", | |||
143 | "Latency Tolerance Reporting", | |||
144 | "Secondary PCIe Capability", | |||
145 | "Protocol Multiplexing", | |||
146 | "Process Address Space ID", | |||
147 | "LN Requester", | |||
148 | "Downstream Port Containment", | |||
149 | "L1 PM", | |||
150 | "Precision Time Measurement", | |||
151 | "PCI Express over M-PHY", | |||
152 | "FRS Queueing", | |||
153 | "Readiness Time Reporting", | |||
154 | "Designated Vendor-Specific", | |||
155 | "VF Resizable BAR", | |||
156 | "Data Link Feature ", | |||
157 | "Physical Layer 16.0 GT/s", | |||
158 | "Lane Margining at the Receiver", | |||
159 | "Hierarchy ID", | |||
160 | "Native PCIe Enclosure Management", | |||
161 | "Physical Layer 32.0 GT/s", | |||
162 | "Alternate Protocol", | |||
163 | "System Firmware Intermediary", | |||
164 | "Shadow Functions", | |||
165 | "Data Object Exchange", | |||
166 | "Device 3", | |||
167 | "Integrity and Data Encryption", | |||
168 | }; | |||
169 | ||||
170 | int | |||
171 | main(int argc, char *argv[]) | |||
172 | { | |||
173 | int nfuncs; | |||
174 | int bus, dev, func; | |||
175 | char pcidev[PATH_MAX1024] = PCIDEV"/dev/pci"; | |||
176 | char *romfile = NULL((void *)0); | |||
177 | const char *errstr; | |||
178 | int c, error = 0, dumpall = 1, domid = 0; | |||
179 | ||||
180 | while ((c = getopt(argc, argv, "d:r:vx")) != -1) { | |||
| ||||
181 | switch (c) { | |||
182 | case 'd': | |||
183 | strlcpy(pcidev, optarg, sizeof(pcidev)); | |||
184 | dumpall = 0; | |||
185 | break; | |||
186 | case 'r': | |||
187 | romfile = optarg; | |||
188 | dumpall = 0; | |||
189 | break; | |||
190 | case 'v': | |||
191 | verbose = 1; | |||
192 | break; | |||
193 | case 'x': | |||
194 | hex++; | |||
195 | break; | |||
196 | default: | |||
197 | usage(); | |||
198 | } | |||
199 | } | |||
200 | argc -= optind; | |||
201 | argv += optind; | |||
202 | ||||
203 | if (argc > 1 || (romfile
| |||
204 | usage(); | |||
205 | ||||
206 | if (romfile
| |||
207 | romfd = open(romfile, O_WRONLY0x0001|O_CREAT0x0200|O_TRUNC0x0400, 0777); | |||
208 | if (romfd == -1) | |||
209 | err(1, "%s", romfile); | |||
210 | } | |||
211 | ||||
212 | if (unveil("/dev", "r") == -1) | |||
213 | err(1, "unveil /dev"); | |||
214 | if (unveil(NULL((void *)0), NULL((void *)0)) == -1) | |||
215 | err(1, "unveil"); | |||
216 | ||||
217 | if (hex
| |||
218 | size = 256; | |||
219 | if (hex
| |||
220 | size = 4096; | |||
221 | ||||
222 | if (argc == 1) | |||
223 | dumpall = 0; | |||
224 | ||||
225 | if (dumpall
| |||
226 | pcifd = open(pcidev, O_RDONLY0x0000); | |||
227 | if (pcifd == -1) | |||
228 | err(1, "%s", pcidev); | |||
229 | } else { | |||
230 | for (;;) { | |||
231 | snprintf(pcidev, 16, "/dev/pci%d", domid++); | |||
232 | pcifd = open(pcidev, O_RDONLY0x0000); | |||
233 | if (pcifd == -1) { | |||
234 | if (errno(*__errno()) == ENXIO6 || errno(*__errno()) == ENOENT2) { | |||
235 | return 0; | |||
236 | } else { | |||
237 | err(1, "%s", pcidev); | |||
238 | } | |||
239 | } | |||
240 | printf("Domain %s:\n", pcidev); | |||
241 | scanpcidomain(); | |||
242 | close(pcifd); | |||
243 | } | |||
244 | } | |||
245 | ||||
246 | if (argc
| |||
247 | errstr = str2busdevfunc(argv[0], &bus, &dev, &func); | |||
248 | if (errstr
| |||
249 | errx(1, "\"%s\": %s", argv[0], errstr); | |||
250 | ||||
251 | nfuncs = pci_nfuncs(bus, dev); | |||
252 | if (nfuncs == -1 || func > nfuncs) | |||
253 | error = ENXIO6; | |||
254 | else if (romfile
| |||
255 | error = dump_rom(bus, dev, func); | |||
256 | else | |||
257 | error = probe(bus, dev, func); | |||
258 | ||||
259 | if (error != 0) | |||
260 | errc(1, error, "\"%s\"", argv[0]); | |||
261 | } else { | |||
262 | printf("Domain %s:\n", pcidev); | |||
263 | scanpcidomain(); | |||
264 | } | |||
265 | ||||
266 | return (0); | |||
267 | } | |||
268 | ||||
269 | void | |||
270 | scanpcidomain(void) | |||
271 | { | |||
272 | int nfuncs; | |||
273 | int bus, dev, func; | |||
274 | ||||
275 | for (bus = 0; bus < 256; bus++) { | |||
276 | for (dev = 0; dev < 32; dev++) { | |||
277 | nfuncs = pci_nfuncs(bus, dev); | |||
278 | for (func = 0; func < nfuncs; func++) { | |||
279 | probe(bus, dev, func); | |||
280 | } | |||
281 | } | |||
282 | } | |||
283 | } | |||
284 | ||||
285 | const char * | |||
286 | str2busdevfunc(const char *string, int *bus, int *dev, int *func) | |||
287 | { | |||
288 | const char *errstr; | |||
289 | char b[80], *d, *f; | |||
290 | ||||
291 | strlcpy(b, string, sizeof(b)); | |||
292 | ||||
293 | d = strchr(b, ':'); | |||
294 | if (d == NULL((void *)0)) | |||
295 | return("device not specified"); | |||
296 | *d++ = '\0'; | |||
297 | ||||
298 | f = strchr(d, ':'); | |||
299 | if (f == NULL((void *)0)) | |||
300 | return("function not specified"); | |||
301 | *f++ = '\0'; | |||
302 | ||||
303 | *bus = strtonum(b, 0, 255, &errstr); | |||
304 | if (errstr != NULL((void *)0)) | |||
305 | return (errstr); | |||
306 | *dev = strtonum(d, 0, 31, &errstr); | |||
307 | if (errstr != NULL((void *)0)) | |||
308 | return (errstr); | |||
309 | *func = strtonum(f, 0, 7, &errstr); | |||
310 | if (errstr != NULL((void *)0)) | |||
311 | return (errstr); | |||
312 | ||||
313 | return (NULL((void *)0)); | |||
314 | } | |||
315 | ||||
316 | int | |||
317 | probe(int bus, int dev, int func) | |||
318 | { | |||
319 | u_int32_t id_reg; | |||
320 | const struct pci_known_vendor *pkv; | |||
321 | const struct pci_known_product *pkp; | |||
322 | const char *vendor = NULL((void *)0), *product = NULL((void *)0); | |||
323 | ||||
324 | if (pci_read(bus, dev, func, PCI_ID_REG0x00, &id_reg) != 0) | |||
325 | return (errno(*__errno())); | |||
326 | ||||
327 | if (PCI_VENDOR(id_reg)(((id_reg) >> 0) & 0xffff) == PCI_VENDOR_INVALID0xffff || | |||
328 | PCI_VENDOR(id_reg)(((id_reg) >> 0) & 0xffff) == 0) | |||
329 | return (ENXIO6); | |||
330 | ||||
331 | for (pkv = pci_known_vendors; pkv->vendorname != NULL((void *)0); pkv++) { | |||
332 | if (pkv->vendor == PCI_VENDOR(id_reg)(((id_reg) >> 0) & 0xffff)) { | |||
333 | vendor = pkv->vendorname; | |||
334 | break; | |||
335 | } | |||
336 | } | |||
337 | ||||
338 | if (vendor
| |||
339 | for (pkp = pci_known_products; pkp->productname != NULL((void *)0); pkp++) | |||
340 | if (pkp->vendor == PCI_VENDOR(id_reg)(((id_reg) >> 0) & 0xffff) && | |||
341 | pkp->product == PCI_PRODUCT(id_reg)(((id_reg) >> 16) & 0xffff)) { | |||
342 | product = pkp->productname; | |||
343 | break; | |||
344 | } | |||
345 | } | |||
346 | ||||
347 | printf(" %d:%d:%d: %s %s\n", bus, dev, func, | |||
348 | (vendor
| |||
349 | (product
| |||
350 | ||||
351 | if (verbose) | |||
352 | dump(bus, dev, func); | |||
353 | if (hex > 0) | |||
354 | hexdump(bus, dev, func, size); | |||
355 | ||||
356 | return (0); | |||
357 | } | |||
358 | ||||
359 | int | |||
360 | print_bytes(const uint8_t *buf, size_t len) | |||
361 | { | |||
362 | char dst[8]; | |||
363 | size_t i; | |||
364 | ||||
365 | for (i = 0; i < len; i++) { | |||
366 | vis(dst, buf[i], VIS_TAB0x08|VIS_NL0x10, 0); | |||
367 | printf("%s", dst); | |||
368 | } | |||
369 | printf("\n"); | |||
370 | ||||
371 | return (0); | |||
372 | } | |||
373 | ||||
374 | int | |||
375 | print_vpd(const uint8_t *buf, size_t len) | |||
376 | { | |||
377 | const struct pci_vpd *vpd; | |||
378 | char key0[8]; | |||
379 | char key1[8]; | |||
380 | size_t vlen; | |||
381 | ||||
382 | while (len > 0) { | |||
383 | if (len < sizeof(*vpd)) | |||
384 | return (1); | |||
385 | ||||
386 | vpd = (const struct pci_vpd *)buf; | |||
387 | vis(key0, vpd->vpd_key0, VIS_TAB0x08|VIS_NL0x10, 0); | |||
388 | vis(key1, vpd->vpd_key1, VIS_TAB0x08|VIS_NL0x10, 0); | |||
389 | vlen = vpd->vpd_len; | |||
390 | ||||
391 | printf("\t\t %s%s: ", key0, key1); | |||
392 | ||||
393 | buf += sizeof(*vpd); | |||
394 | len -= sizeof(*vpd); | |||
395 | ||||
396 | if (len < vlen) | |||
397 | return (1); | |||
398 | print_bytes(buf, vlen); | |||
399 | ||||
400 | buf += vlen; | |||
401 | len -= vlen; | |||
402 | } | |||
403 | ||||
404 | return (0); | |||
405 | } | |||
406 | ||||
407 | void | |||
408 | dump_vpd(int bus, int dev, int func) | |||
409 | { | |||
410 | struct pci_vpd_req io; | |||
411 | uint32_t data[64]; /* XXX this can be up to 32k of data */ | |||
412 | uint8_t *buf = (uint8_t *)data; | |||
413 | size_t len = sizeof(data); | |||
414 | ||||
415 | bzero(&io, sizeof(io)); | |||
416 | io.pv_sel.pc_bus = bus; | |||
417 | io.pv_sel.pc_dev = dev; | |||
418 | io.pv_sel.pc_func = func; | |||
419 | io.pv_offset = 0; | |||
420 | io.pv_count = nitems(data)(sizeof((data)) / sizeof((data)[0])); | |||
421 | io.pv_data = data; | |||
422 | ||||
423 | if (ioctl(pcifd, PCIOCGETVPD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_vpd_req) & 0x1fff) << 16) | ((('p')) << 8) | ((9))), &io) == -1) { | |||
424 | warn("PCIOCGETVPD"); | |||
425 | return; | |||
426 | } | |||
427 | ||||
428 | do { | |||
429 | uint8_t vpd = *buf; | |||
430 | uint8_t type; | |||
431 | size_t hlen, vlen; | |||
432 | int (*print)(const uint8_t *, size_t) = print_bytes; | |||
433 | ||||
434 | if (PCI_VPDRES_ISLARGE(vpd)((vpd) & 0x80)) { | |||
435 | struct pci_vpd_largeres *res; | |||
436 | type = PCI_VPDRES_LARGE_NAME(vpd)((vpd) & 0x7f); | |||
437 | ||||
438 | switch (type) { | |||
439 | case PCI_VPDRES_TYPE_IDENTIFIER_STRING0x02: | |||
440 | printf("\t\tProduct Name: "); | |||
441 | break; | |||
442 | case PCI_VPDRES_TYPE_VPD0x10: | |||
443 | print = print_vpd; | |||
444 | break; | |||
445 | default: | |||
446 | printf("%02x: ", type); | |||
447 | break; | |||
448 | } | |||
449 | ||||
450 | if (len < sizeof(*res)) | |||
451 | goto trunc; | |||
452 | res = (struct pci_vpd_largeres *)buf; | |||
453 | ||||
454 | hlen = sizeof(*res); | |||
455 | vlen = ((size_t)res->vpdres_len_msb << 8) | | |||
456 | (size_t)res->vpdres_len_lsb; | |||
457 | } else { /* small */ | |||
458 | type = PCI_VPDRES_SMALL_NAME(vpd)(((vpd) >> 3) & 0xf); | |||
459 | if (type == PCI_VPDRES_TYPE_END_TAG0xf) | |||
460 | break; | |||
461 | ||||
462 | printf("\t\t"); | |||
463 | switch (type) { | |||
464 | case PCI_VPDRES_TYPE_COMPATIBLE_DEVICE_ID0x3: | |||
465 | case PCI_VPDRES_TYPE_VENDOR_DEFINED0xe: | |||
466 | default: | |||
467 | printf("%02x", type); | |||
468 | break; | |||
469 | } | |||
470 | ||||
471 | hlen = sizeof(vpd); | |||
472 | vlen = PCI_VPDRES_SMALL_LENGTH(vpd)((vpd) & 0x7); | |||
473 | } | |||
474 | buf += hlen; | |||
475 | len -= hlen; | |||
476 | ||||
477 | if (len < vlen) | |||
478 | goto trunc; | |||
479 | (*print)(buf, vlen); | |||
480 | ||||
481 | buf += vlen; | |||
482 | len -= vlen; | |||
483 | } while (len > 0); | |||
484 | ||||
485 | return; | |||
486 | trunc: | |||
487 | /* i have spent too much time in tcpdump - dlg */ | |||
488 | printf("[|vpd]\n"); | |||
489 | } | |||
490 | ||||
491 | void | |||
492 | dump_pci_powerstate(int bus, int dev, int func, uint8_t ptr) | |||
493 | { | |||
494 | u_int32_t pmcsr; | |||
495 | ||||
496 | if (pci_read(bus, dev, func, ptr + PCI_PMCSR0x04, &pmcsr) != 0) | |||
497 | return; | |||
498 | ||||
499 | printf("\t\tState: D%d", pmcsr & PCI_PMCSR_STATE_MASK0x0003); | |||
500 | if (pmcsr & PCI_PMCSR_PME_EN0x0100) | |||
501 | printf(" PME# enabled"); | |||
502 | if (pmcsr & PCI_PMCSR_PME_STATUS0x8000) | |||
503 | printf(" PME# asserted"); | |||
504 | printf("\n"); | |||
505 | } | |||
506 | ||||
507 | static unsigned int | |||
508 | pcie_dcap_mps(uint32_t dcap) | |||
509 | { | |||
510 | uint32_t shift = dcap & 0x7; | |||
511 | return (128 << shift); | |||
512 | } | |||
513 | ||||
514 | static unsigned int | |||
515 | pcie_dcsr_mps(uint32_t dcsr) | |||
516 | { | |||
517 | uint32_t shift = (dcsr >> 5) & 0x7; | |||
518 | return (128 << shift); | |||
519 | } | |||
520 | ||||
521 | static unsigned int | |||
522 | pcie_dcsr_mrrs(uint32_t dcsr) | |||
523 | { | |||
524 | uint32_t shift = (dcsr >> 12) & 0x7; | |||
525 | return (128 << shift); | |||
526 | } | |||
527 | ||||
528 | void | |||
529 | print_pcie_ls(uint8_t speed) | |||
530 | { | |||
531 | if (speed == 6) | |||
532 | printf("64.0"); | |||
533 | else if (speed == 5) | |||
534 | printf("32.0"); | |||
535 | else if (speed == 4) | |||
536 | printf("16.0"); | |||
537 | else if (speed == 3) | |||
538 | printf("8.0"); | |||
539 | else if (speed == 2) | |||
540 | printf("5.0"); | |||
541 | else if (speed == 1) | |||
542 | printf("2.5"); | |||
543 | else | |||
544 | printf("unknown (%d)", speed); | |||
545 | } | |||
546 | ||||
547 | void | |||
548 | dump_pcie_linkspeed(int bus, int dev, int func, uint8_t ptr) | |||
549 | { | |||
550 | u_int32_t dcap, dcsr; | |||
551 | u_int32_t lcap, lcsr; | |||
552 | u_int8_t cwidth, cspeed, swidth, sspeed; | |||
553 | ||||
554 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCAP0x04, &dcap) != 0) | |||
555 | return; | |||
556 | ||||
557 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCSR0x08, &dcsr) != 0) | |||
558 | return; | |||
559 | ||||
560 | printf("\t\tMax Payload Size: %u / %u bytes\n", | |||
561 | pcie_dcsr_mps(dcsr), pcie_dcap_mps(dcap)); | |||
562 | printf("\t\tMax Read Request Size: %u bytes\n", | |||
563 | pcie_dcsr_mrrs(dcsr)); | |||
564 | ||||
565 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP0x0c, &lcap) != 0) | |||
566 | return; | |||
567 | cspeed = lcap & 0x0f; | |||
568 | cwidth = (lcap >> 4) & 0x3f; | |||
569 | if (cwidth == 0) | |||
570 | return; | |||
571 | ||||
572 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCSR0x10, &lcsr) != 0) | |||
573 | return; | |||
574 | sspeed = (lcsr >> 16) & 0x0f; | |||
575 | swidth = (lcsr >> 20) & 0x3f; | |||
576 | ||||
577 | printf("\t\tLink Speed: "); | |||
578 | print_pcie_ls(sspeed); | |||
579 | printf(" / "); | |||
580 | print_pcie_ls(cspeed); | |||
581 | printf(" GT/s\n"); | |||
582 | ||||
583 | printf("\t\tLink Width: x%d / x%d\n", swidth, cwidth); | |||
584 | } | |||
585 | ||||
586 | void | |||
587 | dump_pcie_devserial(int bus, int dev, int func, u_int16_t ptr) | |||
588 | { | |||
589 | uint32_t lower, upper; | |||
590 | uint64_t serial; | |||
591 | ||||
592 | if ((pci_read(bus, dev, func, ptr + 8, &upper) != 0) || | |||
593 | (pci_read(bus, dev, func, ptr + 4, &lower) != 0)) | |||
594 | return; | |||
595 | ||||
596 | serial = ((uint64_t)upper << 32) | (uint64_t)lower; | |||
597 | ||||
598 | printf("\t\tSerial Number: %016llx\n", serial); | |||
599 | } | |||
600 | ||||
601 | void | |||
602 | dump_msi(int bus, int dev, int func, u_int8_t ptr) | |||
603 | { | |||
604 | u_int32_t reg; | |||
605 | ||||
606 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
607 | return; | |||
608 | ||||
609 | printf("\t\tEnabled: %s\n", reg & PCI_MSI_MC_MSIE0x00010000 ? "yes" : "no"); | |||
610 | } | |||
611 | ||||
612 | void | |||
613 | dump_msix(int bus, int dev, int func, u_int8_t ptr) | |||
614 | { | |||
615 | u_int32_t reg; | |||
616 | u_int32_t table; | |||
617 | ||||
618 | if ((pci_read(bus, dev, func, ptr, ®) != 0) || | |||
619 | (pci_read(bus, dev, func, ptr + PCI_MSIX_TABLE0x04, &table) != 0)) | |||
620 | return; | |||
621 | ||||
622 | printf("\t\tEnabled: %s; table size %d (BAR %d:%d)\n", | |||
623 | reg & PCI_MSIX_MC_MSIXE0x80000000 ? "yes" : "no", | |||
624 | PCI_MSIX_MC_TBLSZ(reg)(((reg) & 0x07ff0000) >> 16) + 1, | |||
625 | (table & PCI_MSIX_TABLE_BIR0x00000007), | |||
626 | (table & PCI_MSIX_TABLE_OFF~(0x00000007))); | |||
627 | } | |||
628 | ||||
629 | void | |||
630 | dump_pcie_enhanced_caplist(int bus, int dev, int func) | |||
631 | { | |||
632 | u_int32_t reg; | |||
633 | u_int32_t capidx; | |||
634 | u_int16_t ptr; | |||
635 | u_int16_t ecap; | |||
636 | ||||
637 | ptr = PCI_PCIE_ECAP0x100; | |||
638 | ||||
639 | do { | |||
640 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
641 | return; | |||
642 | ||||
643 | if (PCI_PCIE_ECAP_ID(reg)(((reg) & 0x0000ffff)) == 0xffff && | |||
644 | PCI_PCIE_ECAP_NEXT(reg)(((reg) >> 20) & 0xffc) == PCI_PCIE_ECAP_LAST0x0) | |||
645 | return; | |||
646 | ||||
647 | ecap = PCI_PCIE_ECAP_ID(reg)(((reg) & 0x0000ffff)); | |||
648 | if (ecap >= nitems(pci_enhanced_capnames)(sizeof((pci_enhanced_capnames)) / sizeof((pci_enhanced_capnames )[0]))) | |||
649 | capidx = 0; | |||
650 | else | |||
651 | capidx = ecap; | |||
652 | ||||
653 | printf("\t0x%04x: Enhanced Capability 0x%02x: ", ptr, ecap); | |||
654 | printf("%s\n", pci_enhanced_capnames[capidx]); | |||
655 | ||||
656 | switch (ecap) { | |||
657 | case 0x03: | |||
658 | dump_pcie_devserial(bus, dev, func, ptr); | |||
659 | break; | |||
660 | } | |||
661 | ||||
662 | ptr = PCI_PCIE_ECAP_NEXT(reg)(((reg) >> 20) & 0xffc); | |||
663 | ||||
664 | } while (ptr != PCI_PCIE_ECAP_LAST0x0); | |||
665 | } | |||
666 | ||||
667 | void | |||
668 | dump_caplist(int bus, int dev, int func, u_int8_t ptr) | |||
669 | { | |||
670 | u_int32_t reg; | |||
671 | u_int8_t cap; | |||
672 | ||||
673 | if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG0x04, ®) != 0) | |||
674 | return; | |||
675 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT0x00100000)) | |||
676 | return; | |||
677 | ||||
678 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
679 | return; | |||
680 | ptr = PCI_CAPLIST_PTR(reg)((reg) & 0xff); | |||
681 | while (ptr != 0) { | |||
682 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
683 | return; | |||
684 | cap = PCI_CAPLIST_CAP(reg)((reg) & 0xff); | |||
685 | printf("\t0x%04x: Capability 0x%02x: ", ptr, cap); | |||
686 | if (cap >= nitems(pci_capnames)(sizeof((pci_capnames)) / sizeof((pci_capnames)[0]))) | |||
687 | cap = 0; | |||
688 | printf("%s\n", pci_capnames[cap]); | |||
689 | switch (cap) { | |||
690 | case PCI_CAP_PWRMGMT0x01: | |||
691 | dump_pci_powerstate(bus, dev, func, ptr); | |||
692 | break; | |||
693 | case PCI_CAP_VPD0x03: | |||
694 | dump_vpd(bus, dev, func); | |||
695 | break; | |||
696 | case PCI_CAP_PCIEXPRESS0x10: | |||
697 | dump_pcie_linkspeed(bus, dev, func, ptr); | |||
698 | dump_pcie_enhanced_caplist(bus, dev, func); | |||
699 | break; | |||
700 | case PCI_CAP_MSI0x05: | |||
701 | dump_msi(bus, dev,func, ptr); | |||
702 | break; | |||
703 | case PCI_CAP_MSIX0x11: | |||
704 | dump_msix(bus, dev, func, ptr); | |||
705 | break; | |||
706 | } | |||
707 | ptr = PCI_CAPLIST_NEXT(reg)(((reg) >> 8) & 0xff); | |||
708 | } | |||
709 | } | |||
710 | ||||
711 | void | |||
712 | dump_bars(int bus, int dev, int func, int end) | |||
713 | { | |||
714 | const char *memtype; | |||
715 | u_int64_t mem; | |||
716 | u_int64_t mask; | |||
717 | u_int32_t reg, reg1; | |||
718 | int bar; | |||
719 | ||||
720 | for (bar = PCI_MAPREG_START0x10; bar < end; bar += 0x4) { | |||
721 | if (pci_read(bus, dev, func, bar, ®) != 0 || | |||
722 | pci_readmask(bus, dev, func, bar, ®1) != 0) | |||
723 | warn("unable to read PCI_MAPREG 0x%02x", bar); | |||
724 | ||||
725 | printf("\t0x%04x: BAR ", bar); | |||
726 | ||||
727 | if (reg == 0 && reg1 == 0) { | |||
728 | printf("empty (%08x)\n", reg); | |||
729 | continue; | |||
730 | } | |||
731 | ||||
732 | switch (PCI_MAPREG_TYPE(reg)((reg) & 0x00000001)) { | |||
733 | case PCI_MAPREG_TYPE_MEM0x00000000: | |||
734 | printf("mem "); | |||
735 | if (PCI_MAPREG_MEM_PREFETCHABLE(reg)(((reg) & 0x00000008) != 0)) | |||
736 | printf("prefetchable "); | |||
737 | ||||
738 | memtype = "32bit 1m"; | |||
739 | switch (PCI_MAPREG_MEM_TYPE(reg)((reg) & 0x00000006)) { | |||
740 | case PCI_MAPREG_MEM_TYPE_32BIT0x00000000: | |||
741 | memtype = "32bit"; | |||
742 | case PCI_MAPREG_MEM_TYPE_32BIT_1M0x00000002: | |||
743 | printf("%s ", memtype); | |||
744 | ||||
745 | printf("addr: 0x%08x/0x%08x\n", | |||
746 | PCI_MAPREG_MEM_ADDR(reg)((reg) & 0xfffffff0), | |||
747 | PCI_MAPREG_MEM_SIZE(reg1)(((reg1) & 0xfffffff0) & -((reg1) & 0xfffffff0))); | |||
748 | ||||
749 | break; | |||
750 | case PCI_MAPREG_MEM_TYPE_64BIT0x00000004: | |||
751 | mem = reg; | |||
752 | mask = reg1; | |||
753 | bar += 0x04; | |||
754 | if (pci_read(bus, dev, func, bar, ®) != 0 || | |||
755 | pci_readmask(bus, dev, func, bar, ®1) != 0) | |||
756 | warn("unable to read 0x%02x", bar); | |||
757 | ||||
758 | mem |= (u_int64_t)reg << 32; | |||
759 | mask |= (u_int64_t)reg1 << 32; | |||
760 | ||||
761 | printf("64bit addr: 0x%016llx/0x%08llx\n", | |||
762 | PCI_MAPREG_MEM64_ADDR(mem)((mem) & 0xfffffffffffffff0ULL), | |||
763 | PCI_MAPREG_MEM64_SIZE(mask)(((mask) & 0xfffffffffffffff0ULL) & -((mask) & 0xfffffffffffffff0ULL ))); | |||
764 | ||||
765 | break; | |||
766 | } | |||
767 | break; | |||
768 | ||||
769 | case PCI_MAPREG_TYPE_IO0x00000001: | |||
770 | printf("io addr: 0x%08x/0x%04x\n", | |||
771 | PCI_MAPREG_IO_ADDR(reg)((reg) & 0xfffffffe), | |||
772 | PCI_MAPREG_IO_SIZE(reg1)(((reg1) & 0xfffffffe) & -((reg1) & 0xfffffffe))); | |||
773 | break; | |||
774 | } | |||
775 | } | |||
776 | } | |||
777 | ||||
778 | void | |||
779 | dump_type0(int bus, int dev, int func) | |||
780 | { | |||
781 | u_int32_t reg; | |||
782 | ||||
783 | dump_bars(bus, dev, func, PCI_MAPREG_END0x28); | |||
784 | ||||
785 | if (pci_read(bus, dev, func, PCI_CARDBUS_CIS_REG0x28, ®) != 0) | |||
786 | warn("unable to read PCI_CARDBUS_CIS_REG"); | |||
787 | printf("\t0x%04x: Cardbus CIS: %08x\n", PCI_CARDBUS_CIS_REG0x28, reg); | |||
788 | ||||
789 | if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG0x2c, ®) != 0) | |||
790 | warn("unable to read PCI_SUBSYS_ID_REG"); | |||
791 | printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n", | |||
792 | PCI_SUBSYS_ID_REG0x2c, PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
793 | ||||
794 | if (pci_read(bus, dev, func, PCI_ROM_REG0x30, ®) != 0) | |||
795 | warn("unable to read PCI_ROM_REG"); | |||
796 | printf("\t0x%04x: Expansion ROM Base Address: %08x\n", | |||
797 | PCI_ROM_REG0x30, reg); | |||
798 | ||||
799 | if (pci_read(bus, dev, func, 0x38, ®) != 0) | |||
800 | warn("unable to read 0x38 (reserved)"); | |||
801 | printf("\t0x%04x: %08x\n", 0x38, reg); | |||
802 | ||||
803 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
804 | warn("unable to read PCI_INTERRUPT_REG"); | |||
805 | printf("\t0x%04x: Interrupt Pin: %02x Line: %02x Min Gnt: %02x" | |||
806 | " Max Lat: %02x\n", PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
807 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), PCI_MIN_GNT(reg)(((reg) >> 16) & 0xff), PCI_MAX_LAT(reg)(((reg) >> 24) & 0xff)); | |||
808 | } | |||
809 | ||||
810 | void | |||
811 | dump_type1(int bus, int dev, int func) | |||
812 | { | |||
813 | u_int32_t reg; | |||
814 | ||||
815 | dump_bars(bus, dev, func, PCI_MAPREG_PPB_END0x18); | |||
816 | ||||
817 | if (pci_read(bus, dev, func, PCI_PRIBUS_10x18, ®) != 0) | |||
818 | warn("unable to read PCI_PRIBUS_1"); | |||
819 | printf("\t0x%04x: Primary Bus: %d, Secondary Bus: %d, " | |||
820 | "Subordinate Bus: %d,\n\t\tSecondary Latency Timer: %02x\n", | |||
821 | PCI_PRIBUS_10x18, (reg >> 0) & 0xff, (reg >> 8) & 0xff, | |||
| ||||
822 | (reg >> 16) & 0xff, (reg >> 24) & 0xff); | |||
823 | ||||
824 | if (pci_read(bus, dev, func, PCI_IOBASEL_10x1c, ®) != 0) | |||
825 | warn("unable to read PCI_IOBASEL_1"); | |||
826 | printf("\t0x%04x: I/O Base: %02x, I/O Limit: %02x, " | |||
827 | "Secondary Status: %04x\n", PCI_IOBASEL_10x1c, (reg >> 0 ) & 0xff, | |||
828 | (reg >> 8) & 0xff, (reg >> 16) & 0xffff); | |||
829 | ||||
830 | if (pci_read(bus, dev, func, PCI_MEMBASE_10x20, ®) != 0) | |||
831 | warn("unable to read PCI_MEMBASE_1"); | |||
832 | printf("\t0x%04x: Memory Base: %04x, Memory Limit: %04x\n", | |||
833 | PCI_MEMBASE_10x20, (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
834 | ||||
835 | if (pci_read(bus, dev, func, PCI_PMBASEL_10x24, ®) != 0) | |||
836 | warn("unable to read PCI_PMBASEL_1"); | |||
837 | printf("\t0x%04x: Prefetch Memory Base: %04x, " | |||
838 | "Prefetch Memory Limit: %04x\n", PCI_PMBASEL_10x24, | |||
839 | (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
840 | ||||
841 | #undef PCI_PMBASEH_10x28 | |||
842 | #define PCI_PMBASEH_10x28 0x28 | |||
843 | if (pci_read(bus, dev, func, PCI_PMBASEH_10x28, ®) != 0) | |||
844 | warn("unable to read PCI_PMBASEH_1"); | |||
845 | printf("\t0x%04x: Prefetch Memory Base Upper 32 Bits: %08x\n", | |||
846 | PCI_PMBASEH_10x28, reg); | |||
847 | ||||
848 | #undef PCI_PMLIMITH_10x2c | |||
849 | #define PCI_PMLIMITH_10x2c 0x2c | |||
850 | if (pci_read(bus, dev, func, PCI_PMLIMITH_10x2c, ®) != 0) | |||
851 | warn("unable to read PCI_PMLIMITH_1"); | |||
852 | printf("\t0x%04x: Prefetch Memory Limit Upper 32 Bits: %08x\n", | |||
853 | PCI_PMLIMITH_10x2c, reg); | |||
854 | ||||
855 | #undef PCI_IOBASEH_10x30 | |||
856 | #define PCI_IOBASEH_10x30 0x30 | |||
857 | if (pci_read(bus, dev, func, PCI_IOBASEH_10x30, ®) != 0) | |||
858 | warn("unable to read PCI_IOBASEH_1"); | |||
859 | printf("\t0x%04x: I/O Base Upper 16 Bits: %04x, " | |||
860 | "I/O Limit Upper 16 Bits: %04x\n", PCI_IOBASEH_10x30, | |||
861 | (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
862 | ||||
863 | #define PCI_PPB_ROM_REG0x38 0x38 | |||
864 | if (pci_read(bus, dev, func, PCI_PPB_ROM_REG0x38, ®) != 0) | |||
865 | warn("unable to read PCI_PPB_ROM_REG"); | |||
866 | printf("\t0x%04x: Expansion ROM Base Address: %08x\n", | |||
867 | PCI_PPB_ROM_REG0x38, reg); | |||
868 | ||||
869 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
870 | warn("unable to read PCI_INTERRUPT_REG"); | |||
871 | printf("\t0x%04x: Interrupt Pin: %02x, Line: %02x, " | |||
872 | "Bridge Control: %04x\n", | |||
873 | PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
874 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), reg >> 16); | |||
875 | } | |||
876 | ||||
877 | void | |||
878 | dump_type2(int bus, int dev, int func) | |||
879 | { | |||
880 | u_int32_t reg; | |||
881 | ||||
882 | if (pci_read(bus, dev, func, PCI_MAPREG_START0x10, ®) != 0) | |||
883 | warn("unable to read PCI_MAPREG\n"); | |||
884 | printf("\t0x%04x: Cardbus Control Registers Base Address: %08x\n", | |||
885 | PCI_MAPREG_START0x10, reg); | |||
886 | ||||
887 | if (pci_read(bus, dev, func, PCI_PRIBUS_20x18, ®) != 0) | |||
888 | warn("unable to read PCI_PRIBUS_2"); | |||
889 | printf("\t0x%04x: Primary Bus: %d Cardbus Bus: %d " | |||
890 | "Subordinate Bus: %d \n\t Cardbus Latency Timer: %02x\n", | |||
891 | PCI_PRIBUS_20x18, (reg >> 0) & 0xff, (reg >> 8) & 0xff, | |||
892 | (reg >> 16) & 0xff, (reg >> 24) & 0xff); | |||
893 | ||||
894 | if (pci_read(bus, dev, func, PCI_MEMBASE0_20x1c, ®) != 0) | |||
895 | warn("unable to read PCI_MEMBASE0_2\n"); | |||
896 | printf("\t0x%04x: Memory Base 0: %08x\n", PCI_MEMBASE0_20x1c, reg); | |||
897 | ||||
898 | if (pci_read(bus, dev, func, PCI_MEMLIMIT0_20x20, ®) != 0) | |||
899 | warn("unable to read PCI_MEMLIMIT0_2\n"); | |||
900 | printf("\t0x%04x: Memory Limit 0: %08x\n", PCI_MEMLIMIT0_20x20, reg); | |||
901 | ||||
902 | if (pci_read(bus, dev, func, PCI_MEMBASE1_20x24, ®) != 0) | |||
903 | warn("unable to read PCI_MEMBASE1_2\n"); | |||
904 | printf("\t0x%04x: Memory Base 1: %08x\n", PCI_MEMBASE1_20x24, reg); | |||
905 | ||||
906 | if (pci_read(bus, dev, func, PCI_MEMLIMIT1_20x28, ®) != 0) | |||
907 | warn("unable to read PCI_MEMLIMIT1_2\n"); | |||
908 | printf("\t0x%04x: Memory Limit 1: %08x\n", PCI_MEMLIMIT1_20x28, reg); | |||
909 | ||||
910 | if (pci_read(bus, dev, func, PCI_IOBASE0_20x2c, ®) != 0) | |||
911 | warn("unable to read PCI_IOBASE0_2\n"); | |||
912 | printf("\t0x%04x: I/O Base 0: %08x\n", PCI_IOBASE0_20x2c, reg); | |||
913 | ||||
914 | if (pci_read(bus, dev, func, PCI_IOLIMIT0_20x30, ®) != 0) | |||
915 | warn("unable to read PCI_IOLIMIT0_2\n"); | |||
916 | printf("\t0x%04x: I/O Limit 0: %08x\n", PCI_IOLIMIT0_20x30, reg); | |||
917 | ||||
918 | if (pci_read(bus, dev, func, PCI_IOBASE1_20x34, ®) != 0) | |||
919 | warn("unable to read PCI_IOBASE1_2\n"); | |||
920 | printf("\t0x%04x: I/O Base 1: %08x\n", PCI_IOBASE1_20x34, reg); | |||
921 | ||||
922 | if (pci_read(bus, dev, func, PCI_IOLIMIT1_20x38, ®) != 0) | |||
923 | warn("unable to read PCI_IOLIMIT1_2\n"); | |||
924 | printf("\t0x%04x: I/O Limit 1: %08x\n", PCI_IOLIMIT1_20x38, reg); | |||
925 | ||||
926 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
927 | warn("unable to read PCI_INTERRUPT_REG"); | |||
928 | printf("\t0x%04x: Interrupt Pin: %02x Line: %02x " | |||
929 | "Bridge Control: %04x\n", | |||
930 | PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
931 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), reg >> 16); | |||
932 | ||||
933 | if (pci_read(bus, dev, func, PCI_SUBVEND_20x40, ®) != 0) | |||
934 | warn("unable to read PCI_SUBVEND_2"); | |||
935 | printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n", | |||
936 | PCI_SUBVEND_20x40, PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
937 | ||||
938 | if (pci_read(bus, dev, func, PCI_PCCARDIF_20x44, ®) != 0) | |||
939 | warn("unable to read PCI_PCCARDIF_2\n"); | |||
940 | printf("\t0x%04x: 16-bit Legacy Mode Base Address: %08x\n", | |||
941 | PCI_PCCARDIF_20x44, reg); | |||
942 | } | |||
943 | ||||
944 | void | |||
945 | dump(int bus, int dev, int func) | |||
946 | { | |||
947 | u_int32_t reg; | |||
948 | u_int8_t capptr = PCI_CAPLISTPTR_REG0x34; | |||
949 | pci_class_t class; | |||
950 | pci_subclass_t subclass; | |||
951 | ||||
952 | if (pci_read(bus, dev, func, PCI_ID_REG0x00, ®) != 0) | |||
953 | warn("unable to read PCI_ID_REG"); | |||
954 | printf("\t0x%04x: Vendor ID: %04x, Product ID: %04x\n", PCI_ID_REG0x00, | |||
955 | PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
956 | ||||
957 | if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG0x04, ®) != 0) | |||
958 | warn("unable to read PCI_COMMAND_STATUS_REG"); | |||
959 | printf("\t0x%04x: Command: %04x, Status: %04x\n", | |||
960 | PCI_COMMAND_STATUS_REG0x04, reg & 0xffff, (reg >> 16) & 0xffff); | |||
961 | ||||
962 | if (pci_read(bus, dev, func, PCI_CLASS_REG0x08, ®) != 0) | |||
963 | warn("unable to read PCI_CLASS_REG"); | |||
964 | class = PCI_CLASS(reg)(((reg) >> 24) & 0xff); | |||
965 | subclass = PCI_SUBCLASS(reg)(((reg) >> 16) & 0xff); | |||
966 | printf("\t0x%04x:\tClass: %02x %s,", PCI_CLASS_REG0x08, class, | |||
967 | pci_class_name(class)); | |||
968 | printf(" Subclass: %02x %s,", subclass, | |||
969 | pci_subclass_name(class, subclass)); | |||
970 | printf("\n\t\tInterface: %02x, Revision: %02x\n", | |||
971 | PCI_INTERFACE(reg)(((reg) >> 8) & 0xff), PCI_REVISION(reg)(((reg) >> 0) & 0xff)); | |||
972 | ||||
973 | if (pci_read(bus, dev, func, PCI_BHLC_REG0x0c, ®) != 0) | |||
974 | warn("unable to read PCI_BHLC_REG"); | |||
975 | printf("\t0x%04x: BIST: %02x, Header Type: %02x, " | |||
976 | "Latency Timer: %02x,\n\t\tCache Line Size: %02x\n", PCI_BHLC_REG0x0c, | |||
977 | PCI_BIST(reg)(((reg) >> 24) & 0xff), PCI_HDRTYPE(reg)(((reg) >> 16) & 0xff), | |||
978 | PCI_LATTIMER(reg)(((reg) >> 8) & 0xff), PCI_CACHELINE(reg)(((reg) >> 0) & 0xff)); | |||
979 | ||||
980 | switch (PCI_HDRTYPE_TYPE(reg)((((reg) >> 16) & 0xff) & 0x7f)) { | |||
981 | case 2: | |||
982 | dump_type2(bus, dev, func); | |||
983 | capptr = PCI_CARDBUS_CAPLISTPTR_REG0x14; | |||
984 | break; | |||
985 | case 1: | |||
986 | dump_type1(bus, dev, func); | |||
987 | break; | |||
988 | case 0: | |||
989 | dump_type0(bus, dev, func); | |||
990 | break; | |||
991 | default: | |||
992 | break; | |||
993 | } | |||
994 | dump_caplist(bus, dev, func, capptr); | |||
995 | } | |||
996 | ||||
997 | void | |||
998 | hexdump(int bus, int dev, int func, int size) | |||
999 | { | |||
1000 | u_int32_t reg; | |||
1001 | int i; | |||
1002 | ||||
1003 | for (i = 0; i < size; i += 4) { | |||
1004 | if (pci_read(bus, dev, func, i, ®) != 0) { | |||
1005 | if (errno(*__errno()) == EINVAL22) | |||
1006 | return; | |||
1007 | warn("unable to read 0x%02x", i); | |||
1008 | } | |||
1009 | ||||
1010 | if ((i % 16) == 0) | |||
1011 | printf("\t0x%04x:", i); | |||
1012 | printf(" %08x", reg); | |||
1013 | ||||
1014 | if ((i % 16) == 12) | |||
1015 | printf("\n"); | |||
1016 | } | |||
1017 | } | |||
1018 | ||||
1019 | int | |||
1020 | pci_nfuncs(int bus, int dev) | |||
1021 | { | |||
1022 | u_int32_t hdr; | |||
1023 | ||||
1024 | if (pci_read(bus, dev, 0, PCI_BHLC_REG0x0c, &hdr) != 0) | |||
1025 | return (-1); | |||
1026 | ||||
1027 | return (PCI_HDRTYPE_MULTIFN(hdr)(((((hdr) >> 16) & 0xff) & 0x80) != 0) ? 8 : 1); | |||
1028 | } | |||
1029 | ||||
1030 | int | |||
1031 | pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val) | |||
1032 | { | |||
1033 | struct pci_io io; | |||
1034 | int rv; | |||
1035 | ||||
1036 | bzero(&io, sizeof(io)); | |||
1037 | io.pi_sel.pc_bus = bus; | |||
1038 | io.pi_sel.pc_dev = dev; | |||
1039 | io.pi_sel.pc_func = func; | |||
1040 | io.pi_reg = reg; | |||
1041 | io.pi_width = 4; | |||
1042 | ||||
1043 | rv = ioctl(pcifd, PCIOCREAD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_io) & 0x1fff) << 16) | ((('p')) << 8) | ((2))), &io); | |||
1044 | if (rv != 0) | |||
1045 | return (rv); | |||
1046 | ||||
1047 | *val = io.pi_data; | |||
1048 | ||||
1049 | return (0); | |||
1050 | } | |||
1051 | ||||
1052 | int | |||
1053 | pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val) | |||
1054 | { | |||
1055 | struct pci_io io; | |||
1056 | int rv; | |||
1057 | ||||
1058 | bzero(&io, sizeof(io)); | |||
1059 | io.pi_sel.pc_bus = bus; | |||
1060 | io.pi_sel.pc_dev = dev; | |||
1061 | io.pi_sel.pc_func = func; | |||
1062 | io.pi_reg = reg; | |||
1063 | io.pi_width = 4; | |||
1064 | ||||
1065 | rv = ioctl(pcifd, PCIOCREADMASK(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_io) & 0x1fff) << 16) | ((('p')) << 8) | ((8))), &io); | |||
1066 | if (rv != 0) | |||
1067 | return (rv); | |||
1068 | ||||
1069 | *val = io.pi_data; | |||
1070 | ||||
1071 | return (0); | |||
1072 | } | |||
1073 | ||||
1074 | int | |||
1075 | dump_rom(int bus, int dev, int func) | |||
1076 | { | |||
1077 | struct pci_rom rom; | |||
1078 | u_int32_t cr, addr; | |||
1079 | ||||
1080 | if (pci_read(bus, dev, func, PCI_ROM_REG0x30, &addr) != 0 || | |||
1081 | pci_read(bus, dev, func, PCI_CLASS_REG0x08, &cr) != 0) | |||
1082 | return (errno(*__errno())); | |||
1083 | ||||
1084 | if (addr == 0 && PCI_CLASS(cr)(((cr) >> 24) & 0xff) == PCI_CLASS_DISPLAY0x03 && | |||
1085 | PCI_SUBCLASS(cr)(((cr) >> 16) & 0xff) == PCI_SUBCLASS_DISPLAY_VGA0x00) | |||
1086 | return dump_vga_bios(); | |||
1087 | ||||
1088 | bzero(&rom, sizeof(rom)); | |||
1089 | rom.pr_sel.pc_bus = bus; | |||
1090 | rom.pr_sel.pc_dev = dev; | |||
1091 | rom.pr_sel.pc_func = func; | |||
1092 | if (ioctl(pcifd, PCIOCGETROMLEN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_rom) & 0x1fff) << 16) | ((('p')) << 8) | ((4))), &rom) == -1) | |||
1093 | return (errno(*__errno())); | |||
1094 | ||||
1095 | rom.pr_rom = malloc(rom.pr_romlen); | |||
1096 | if (rom.pr_rom == NULL((void *)0)) | |||
1097 | return (ENOMEM12); | |||
1098 | ||||
1099 | if (ioctl(pcifd, PCIOCGETROM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_rom) & 0x1fff) << 16) | ((('p')) << 8) | ((5))), &rom) == -1) | |||
1100 | return (errno(*__errno())); | |||
1101 | ||||
1102 | if (write(romfd, rom.pr_rom, rom.pr_romlen) == -1) | |||
1103 | return (errno(*__errno())); | |||
1104 | ||||
1105 | return (0); | |||
1106 | } | |||
1107 | ||||
1108 | #define VGA_BIOS_ADDR0xc0000 0xc0000 | |||
1109 | #define VGA_BIOS_LEN0x10000 0x10000 | |||
1110 | ||||
1111 | int | |||
1112 | dump_vga_bios(void) | |||
1113 | { | |||
1114 | #if defined(__amd64__1) || defined(__i386__) | |||
1115 | void *bios; | |||
1116 | int fd; | |||
1117 | ||||
1118 | fd = open(_PATH_MEM"/dev/mem", O_RDONLY0x0000); | |||
1119 | if (fd == -1) | |||
1120 | err(1, "%s", _PATH_MEM"/dev/mem"); | |||
1121 | ||||
1122 | bios = malloc(VGA_BIOS_LEN0x10000); | |||
1123 | if (bios == NULL((void *)0)) | |||
1124 | return (ENOMEM12); | |||
1125 | ||||
1126 | if (pread(fd, bios, VGA_BIOS_LEN0x10000, VGA_BIOS_ADDR0xc0000) == -1) | |||
1127 | err(1, "%s", _PATH_MEM"/dev/mem"); | |||
1128 | ||||
1129 | if (write(romfd, bios, VGA_BIOS_LEN0x10000) == -1) { | |||
1130 | free(bios); | |||
1131 | return (errno(*__errno())); | |||
1132 | } | |||
1133 | ||||
1134 | free(bios); | |||
1135 | ||||
1136 | return (0); | |||
1137 | #else | |||
1138 | return (ENODEV19); | |||
1139 | #endif | |||
1140 | } | |||
1141 | ||||
1142 | struct pci_subclass { | |||
1143 | pci_subclass_t subclass; | |||
1144 | const char *name; | |||
1145 | }; | |||
1146 | ||||
1147 | struct pci_class { | |||
1148 | pci_class_t class; | |||
1149 | const char *name; | |||
1150 | const struct pci_subclass | |||
1151 | *subclass; | |||
1152 | size_t nsubclass; | |||
1153 | }; | |||
1154 | ||||
1155 | static const struct pci_subclass pci_subclass_prehistoric[] = { | |||
1156 | { PCI_SUBCLASS_PREHISTORIC_MISC0x00, "Miscellaneous" }, | |||
1157 | { PCI_SUBCLASS_PREHISTORIC_VGA0x01, "VGA" }, | |||
1158 | }; | |||
1159 | ||||
1160 | static const struct pci_subclass pci_subclass_mass_storage[] = { | |||
1161 | { PCI_SUBCLASS_MASS_STORAGE_SCSI0x00, "SCSI" }, | |||
1162 | { PCI_SUBCLASS_MASS_STORAGE_IDE0x01, "IDE" }, | |||
1163 | { PCI_SUBCLASS_MASS_STORAGE_FLOPPY0x02, "Floppy" }, | |||
1164 | { PCI_SUBCLASS_MASS_STORAGE_IPI0x03, "IPI" }, | |||
1165 | { PCI_SUBCLASS_MASS_STORAGE_RAID0x04, "RAID" }, | |||
1166 | { PCI_SUBCLASS_MASS_STORAGE_ATA0x05, "ATA" }, | |||
1167 | { PCI_SUBCLASS_MASS_STORAGE_SATA0x06, "SATA" }, | |||
1168 | { PCI_SUBCLASS_MASS_STORAGE_SAS0x07, "SAS" }, | |||
1169 | { PCI_SUBCLASS_MASS_STORAGE_UFS0x09, "UFS" }, | |||
1170 | { PCI_SUBCLASS_MASS_STORAGE_NVM0x08, "NVM" }, | |||
1171 | { PCI_SUBCLASS_MASS_STORAGE_MISC0x80, "Miscellaneous" }, | |||
1172 | }; | |||
1173 | ||||
1174 | static const struct pci_subclass pci_subclass_network[] = { | |||
1175 | { PCI_SUBCLASS_NETWORK_ETHERNET0x00, "Ethernet" }, | |||
1176 | { PCI_SUBCLASS_NETWORK_TOKENRING0x01, "Token Ring" }, | |||
1177 | { PCI_SUBCLASS_NETWORK_FDDI0x02, "FDDI" }, | |||
1178 | { PCI_SUBCLASS_NETWORK_ATM0x03, "ATM" }, | |||
1179 | { PCI_SUBCLASS_NETWORK_ISDN0x04, "ISDN" }, | |||
1180 | { PCI_SUBCLASS_NETWORK_WORLDFIP0x05, "WorldFip" }, | |||
1181 | { PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP0x06, "PCMIG Multi Computing" }, | |||
1182 | { PCI_SUBCLASS_NETWORK_INFINIBAND0x07, "InfiniBand" }, | |||
1183 | { PCI_SUBCLASS_NETWORK_MISC0x80, "Miscellaneous" }, | |||
1184 | }; | |||
1185 | ||||
1186 | static const struct pci_subclass pci_subclass_display[] = { | |||
1187 | { PCI_SUBCLASS_DISPLAY_VGA0x00, "VGA" }, | |||
1188 | { PCI_SUBCLASS_DISPLAY_XGA0x01, "XGA" }, | |||
1189 | { PCI_SUBCLASS_DISPLAY_3D0x02, "3D" }, | |||
1190 | { PCI_SUBCLASS_DISPLAY_MISC0x80, "Miscellaneous" }, | |||
1191 | }; | |||
1192 | ||||
1193 | static const struct pci_subclass pci_subclass_multimedia[] = { | |||
1194 | { PCI_SUBCLASS_MULTIMEDIA_VIDEO0x00, "Video" }, | |||
1195 | { PCI_SUBCLASS_MULTIMEDIA_AUDIO0x01, "Audio" }, | |||
1196 | { PCI_SUBCLASS_MULTIMEDIA_TELEPHONY0x02, "Telephony" }, | |||
1197 | { PCI_SUBCLASS_MULTIMEDIA_HDAUDIO0x03, "HD Audio" }, | |||
1198 | { PCI_SUBCLASS_MULTIMEDIA_MISC0x80, "Miscellaneous" }, | |||
1199 | }; | |||
1200 | ||||
1201 | static const struct pci_subclass pci_subclass_memory[] = { | |||
1202 | { PCI_SUBCLASS_MEMORY_RAM0x00, "RAM" }, | |||
1203 | { PCI_SUBCLASS_MEMORY_FLASH0x01, "Flash" }, | |||
1204 | { PCI_SUBCLASS_MEMORY_MISC0x80, "Miscellaneous" }, | |||
1205 | }; | |||
1206 | ||||
1207 | static const struct pci_subclass pci_subclass_bridge[] = { | |||
1208 | { PCI_SUBCLASS_BRIDGE_HOST0x00, "Host" }, | |||
1209 | { PCI_SUBCLASS_BRIDGE_ISA0x01, "ISA" }, | |||
1210 | { PCI_SUBCLASS_BRIDGE_EISA0x02, "EISA" }, | |||
1211 | { PCI_SUBCLASS_BRIDGE_MC0x03, "MicroChannel" }, | |||
1212 | { PCI_SUBCLASS_BRIDGE_PCI0x04, "PCI" }, | |||
1213 | { PCI_SUBCLASS_BRIDGE_PCMCIA0x05, "PCMCIA" }, | |||
1214 | { PCI_SUBCLASS_BRIDGE_NUBUS0x06, "NuBus" }, | |||
1215 | { PCI_SUBCLASS_BRIDGE_RACEWAY0x08, "RACEway" }, | |||
1216 | { PCI_SUBCLASS_BRIDGE_STPCI0x09, "Semi-transparent PCI" }, | |||
1217 | { PCI_SUBCLASS_BRIDGE_INFINIBAND0x0a, "InfiniBand" }, | |||
1218 | { PCI_SUBCLASS_BRIDGE_MISC0x80, "Miscellaneous" }, | |||
1219 | { PCI_SUBCLASS_BRIDGE_AS0x0b, "advanced switching" }, | |||
1220 | }; | |||
1221 | ||||
1222 | static const struct pci_subclass pci_subclass_communications[] = { | |||
1223 | { PCI_SUBCLASS_COMMUNICATIONS_SERIAL0x00, "Serial" }, | |||
1224 | { PCI_SUBCLASS_COMMUNICATIONS_PARALLEL0x01, "Parallel" }, | |||
1225 | { PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL0x02, "Multi-port Serial" }, | |||
1226 | { PCI_SUBCLASS_COMMUNICATIONS_MODEM0x03, "Modem" }, | |||
1227 | { PCI_SUBCLASS_COMMUNICATIONS_GPIB0x04, "GPIB" }, | |||
1228 | { PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD0x05, | |||
1229 | "Smartcard" }, | |||
1230 | { PCI_SUBCLASS_COMMUNICATIONS_MISC0x80, "Miscellaneous" }, | |||
1231 | }; | |||
1232 | ||||
1233 | static const struct pci_subclass pci_subclass_system[] = { | |||
1234 | { PCI_SUBCLASS_SYSTEM_PIC0x00, "Interrupt" }, | |||
1235 | { PCI_SUBCLASS_SYSTEM_DMA0x01, "8237 DMA" }, | |||
1236 | { PCI_SUBCLASS_SYSTEM_TIMER0x02, "8254 Timer" }, | |||
1237 | { PCI_SUBCLASS_SYSTEM_RTC0x03, "RTC" }, | |||
1238 | { PCI_SUBCLASS_SYSTEM_SDHC0x05, "SDHC" }, | |||
1239 | { PCI_SUBCLASS_SYSTEM_IOMMU0x06, "IOMMU" }, | |||
1240 | { PCI_SUBCLASS_SYSTEM_ROOTCOMPEVENT0x07, "Root Complex Event" }, | |||
1241 | { PCI_SUBCLASS_SYSTEM_MISC0x80, "Miscellaneous" }, | |||
1242 | }; | |||
1243 | ||||
1244 | static const struct pci_subclass pci_subclass_input[] = { | |||
1245 | { PCI_SUBCLASS_INPUT_KEYBOARD0x00, "Keyboard" }, | |||
1246 | { PCI_SUBCLASS_INPUT_DIGITIZER0x01, "Digitizer" }, | |||
1247 | { PCI_SUBCLASS_INPUT_MOUSE0x02, "Mouse" }, | |||
1248 | { PCI_SUBCLASS_INPUT_SCANNER0x03, "Scanner" }, | |||
1249 | { PCI_SUBCLASS_INPUT_GAMEPORT0x04, "Game Port" }, | |||
1250 | { PCI_SUBCLASS_INPUT_MISC0x80, "Miscellaneous" }, | |||
1251 | }; | |||
1252 | ||||
1253 | static const struct pci_subclass pci_subclass_dock[] = { | |||
1254 | { PCI_SUBCLASS_DOCK_GENERIC0x00, "Generic" }, | |||
1255 | { PCI_SUBCLASS_DOCK_MISC0x80, "Miscellaneous" }, | |||
1256 | }; | |||
1257 | ||||
1258 | static const struct pci_subclass pci_subclass_processor[] = { | |||
1259 | { PCI_SUBCLASS_PROCESSOR_3860x00, "386" }, | |||
1260 | { PCI_SUBCLASS_PROCESSOR_4860x01, "486" }, | |||
1261 | { PCI_SUBCLASS_PROCESSOR_PENTIUM0x02, "Pentium" }, | |||
1262 | { PCI_SUBCLASS_PROCESSOR_ALPHA0x10, "Alpha" }, | |||
1263 | { PCI_SUBCLASS_PROCESSOR_POWERPC0x20, "PowerPC" }, | |||
1264 | { PCI_SUBCLASS_PROCESSOR_MIPS0x30, "MIPS" }, | |||
1265 | { PCI_SUBCLASS_PROCESSOR_COPROC0x40, "Co-Processor" }, | |||
1266 | }; | |||
1267 | ||||
1268 | static const struct pci_subclass pci_subclass_serialbus[] = { | |||
1269 | { PCI_SUBCLASS_SERIALBUS_FIREWIRE0x00, "FireWire" }, | |||
1270 | { PCI_SUBCLASS_SERIALBUS_ACCESS0x01, "ACCESS.bus" }, | |||
1271 | { PCI_SUBCLASS_SERIALBUS_SSA0x02, "SSA" }, | |||
1272 | { PCI_SUBCLASS_SERIALBUS_USB0x03, "USB" }, | |||
1273 | { PCI_SUBCLASS_SERIALBUS_FIBER0x04, "Fiber Channel" }, | |||
1274 | { PCI_SUBCLASS_SERIALBUS_SMBUS0x05, "SMBus" }, | |||
1275 | { PCI_SUBCLASS_SERIALBUS_INFINIBAND0x06, "InfiniBand" }, | |||
1276 | { PCI_SUBCLASS_SERIALBUS_IPMI0x07, "IPMI" }, | |||
1277 | { PCI_SUBCLASS_SERIALBUS_SERCOS0x08, "SERCOS" }, | |||
1278 | { PCI_SUBCLASS_SERIALBUS_CANBUS0x09, "CANbus" }, | |||
1279 | }; | |||
1280 | ||||
1281 | static const struct pci_subclass pci_subclass_wireless[] = { | |||
1282 | { PCI_SUBCLASS_WIRELESS_IRDA0x00, "IrDA" }, | |||
1283 | { PCI_SUBCLASS_WIRELESS_CONSUMERIR0x01, "Consumer IR" }, | |||
1284 | { PCI_SUBCLASS_WIRELESS_RF0x10, "RF" }, | |||
1285 | { PCI_SUBCLASS_WIRELESS_BLUETOOTH0x11, "Bluetooth" }, | |||
1286 | { PCI_SUBCLASS_WIRELESS_BROADBAND0x12, "Broadband" }, | |||
1287 | { PCI_SUBCLASS_WIRELESS_802_11A0x20, "802.11a" }, | |||
1288 | { PCI_SUBCLASS_WIRELESS_802_11B0x21, "802.11b" }, | |||
1289 | { PCI_SUBCLASS_WIRELESS_MISC0x80, "Miscellaneous" }, | |||
1290 | }; | |||
1291 | ||||
1292 | static const struct pci_subclass pci_subclass_i2o[] = { | |||
1293 | { PCI_SUBCLASS_I2O_STANDARD0x00, "Standard" }, | |||
1294 | }; | |||
1295 | ||||
1296 | static const struct pci_subclass pci_subclass_satcom[] = { | |||
1297 | { PCI_SUBCLASS_SATCOM_TV0x01, "TV" }, | |||
1298 | { PCI_SUBCLASS_SATCOM_AUDIO0x02, "Audio" }, | |||
1299 | { PCI_SUBCLASS_SATCOM_VOICE0x03, "Voice" }, | |||
1300 | { PCI_SUBCLASS_SATCOM_DATA0x04, "Data" }, | |||
1301 | }; | |||
1302 | ||||
1303 | static const struct pci_subclass pci_subclass_crypto[] = { | |||
1304 | { PCI_SUBCLASS_CRYPTO_NETCOMP0x00, "Network/Computing" }, | |||
1305 | { PCI_SUBCLASS_CRYPTO_ENTERTAINMENT0x10, "Entertainment" }, | |||
1306 | { PCI_SUBCLASS_CRYPTO_MISC0x80, "Miscellaneous" }, | |||
1307 | }; | |||
1308 | ||||
1309 | static const struct pci_subclass pci_subclass_dasp[] = { | |||
1310 | { PCI_SUBCLASS_DASP_DPIO0x00, "DPIO" }, | |||
1311 | { PCI_SUBCLASS_DASP_TIMEFREQ0x01, "Time and Frequency" }, | |||
1312 | { PCI_SUBCLASS_DASP_SYNC0x10, "Synchronization" }, | |||
1313 | { PCI_SUBCLASS_DASP_MGMT0x20, "Management" }, | |||
1314 | { PCI_SUBCLASS_DASP_MISC0x80, "Miscellaneous" }, | |||
1315 | }; | |||
1316 | ||||
1317 | static const struct pci_subclass pci_subclass_accelerator[] = {}; | |||
1318 | static const struct pci_subclass pci_subclass_instrumentation[] = {}; | |||
1319 | ||||
1320 | #define CLASS(_c, _n, _s){ .class = _c, .name = _n, .subclass = _s, .nsubclass = (sizeof ((_s)) / sizeof((_s)[0])), } { \ | |||
1321 | .class = _c, \ | |||
1322 | .name = _n, \ | |||
1323 | .subclass = _s, \ | |||
1324 | .nsubclass = nitems(_s)(sizeof((_s)) / sizeof((_s)[0])), \ | |||
1325 | } | |||
1326 | ||||
1327 | static const struct pci_class pci_classes[] = { | |||
1328 | CLASS(PCI_CLASS_PREHISTORIC, "Prehistoric",{ .class = 0x00, .name = "Prehistoric", .subclass = pci_subclass_prehistoric , .nsubclass = (sizeof((pci_subclass_prehistoric)) / sizeof(( pci_subclass_prehistoric)[0])), } | |||
1329 | pci_subclass_prehistoric){ .class = 0x00, .name = "Prehistoric", .subclass = pci_subclass_prehistoric , .nsubclass = (sizeof((pci_subclass_prehistoric)) / sizeof(( pci_subclass_prehistoric)[0])), }, | |||
1330 | CLASS(PCI_CLASS_MASS_STORAGE, "Mass Storage",{ .class = 0x01, .name = "Mass Storage", .subclass = pci_subclass_mass_storage , .nsubclass = (sizeof((pci_subclass_mass_storage)) / sizeof( (pci_subclass_mass_storage)[0])), } | |||
1331 | pci_subclass_mass_storage){ .class = 0x01, .name = "Mass Storage", .subclass = pci_subclass_mass_storage , .nsubclass = (sizeof((pci_subclass_mass_storage)) / sizeof( (pci_subclass_mass_storage)[0])), }, | |||
1332 | CLASS(PCI_CLASS_NETWORK, "Network",{ .class = 0x02, .name = "Network", .subclass = pci_subclass_network , .nsubclass = (sizeof((pci_subclass_network)) / sizeof((pci_subclass_network )[0])), } | |||
1333 | pci_subclass_network){ .class = 0x02, .name = "Network", .subclass = pci_subclass_network , .nsubclass = (sizeof((pci_subclass_network)) / sizeof((pci_subclass_network )[0])), }, | |||
1334 | CLASS(PCI_CLASS_DISPLAY, "Display",{ .class = 0x03, .name = "Display", .subclass = pci_subclass_display , .nsubclass = (sizeof((pci_subclass_display)) / sizeof((pci_subclass_display )[0])), } | |||
1335 | pci_subclass_display){ .class = 0x03, .name = "Display", .subclass = pci_subclass_display , .nsubclass = (sizeof((pci_subclass_display)) / sizeof((pci_subclass_display )[0])), }, | |||
1336 | CLASS(PCI_CLASS_MULTIMEDIA, "Multimedia",{ .class = 0x04, .name = "Multimedia", .subclass = pci_subclass_multimedia , .nsubclass = (sizeof((pci_subclass_multimedia)) / sizeof((pci_subclass_multimedia )[0])), } | |||
1337 | pci_subclass_multimedia){ .class = 0x04, .name = "Multimedia", .subclass = pci_subclass_multimedia , .nsubclass = (sizeof((pci_subclass_multimedia)) / sizeof((pci_subclass_multimedia )[0])), }, | |||
1338 | CLASS(PCI_CLASS_MEMORY, "Memory",{ .class = 0x05, .name = "Memory", .subclass = pci_subclass_memory , .nsubclass = (sizeof((pci_subclass_memory)) / sizeof((pci_subclass_memory )[0])), } | |||
1339 | pci_subclass_memory){ .class = 0x05, .name = "Memory", .subclass = pci_subclass_memory , .nsubclass = (sizeof((pci_subclass_memory)) / sizeof((pci_subclass_memory )[0])), }, | |||
1340 | CLASS(PCI_CLASS_BRIDGE, "Bridge",{ .class = 0x06, .name = "Bridge", .subclass = pci_subclass_bridge , .nsubclass = (sizeof((pci_subclass_bridge)) / sizeof((pci_subclass_bridge )[0])), } | |||
1341 | pci_subclass_bridge){ .class = 0x06, .name = "Bridge", .subclass = pci_subclass_bridge , .nsubclass = (sizeof((pci_subclass_bridge)) / sizeof((pci_subclass_bridge )[0])), }, | |||
1342 | CLASS(PCI_CLASS_COMMUNICATIONS, "Communications",{ .class = 0x07, .name = "Communications", .subclass = pci_subclass_communications , .nsubclass = (sizeof((pci_subclass_communications)) / sizeof ((pci_subclass_communications)[0])), } | |||
1343 | pci_subclass_communications){ .class = 0x07, .name = "Communications", .subclass = pci_subclass_communications , .nsubclass = (sizeof((pci_subclass_communications)) / sizeof ((pci_subclass_communications)[0])), }, | |||
1344 | CLASS(PCI_CLASS_SYSTEM, "System",{ .class = 0x08, .name = "System", .subclass = pci_subclass_system , .nsubclass = (sizeof((pci_subclass_system)) / sizeof((pci_subclass_system )[0])), } | |||
1345 | pci_subclass_system){ .class = 0x08, .name = "System", .subclass = pci_subclass_system , .nsubclass = (sizeof((pci_subclass_system)) / sizeof((pci_subclass_system )[0])), }, | |||
1346 | CLASS(PCI_CLASS_INPUT, "Input",{ .class = 0x09, .name = "Input", .subclass = pci_subclass_input , .nsubclass = (sizeof((pci_subclass_input)) / sizeof((pci_subclass_input )[0])), } | |||
1347 | pci_subclass_input){ .class = 0x09, .name = "Input", .subclass = pci_subclass_input , .nsubclass = (sizeof((pci_subclass_input)) / sizeof((pci_subclass_input )[0])), }, | |||
1348 | CLASS(PCI_CLASS_DOCK, "Dock",{ .class = 0x0a, .name = "Dock", .subclass = pci_subclass_dock , .nsubclass = (sizeof((pci_subclass_dock)) / sizeof((pci_subclass_dock )[0])), } | |||
1349 | pci_subclass_dock){ .class = 0x0a, .name = "Dock", .subclass = pci_subclass_dock , .nsubclass = (sizeof((pci_subclass_dock)) / sizeof((pci_subclass_dock )[0])), }, | |||
1350 | CLASS(PCI_CLASS_PROCESSOR, "Processor",{ .class = 0x0b, .name = "Processor", .subclass = pci_subclass_processor , .nsubclass = (sizeof((pci_subclass_processor)) / sizeof((pci_subclass_processor )[0])), } | |||
1351 | pci_subclass_processor){ .class = 0x0b, .name = "Processor", .subclass = pci_subclass_processor , .nsubclass = (sizeof((pci_subclass_processor)) / sizeof((pci_subclass_processor )[0])), }, | |||
1352 | CLASS(PCI_CLASS_SERIALBUS, "Serial Bus",{ .class = 0x0c, .name = "Serial Bus", .subclass = pci_subclass_serialbus , .nsubclass = (sizeof((pci_subclass_serialbus)) / sizeof((pci_subclass_serialbus )[0])), } | |||
1353 | pci_subclass_serialbus){ .class = 0x0c, .name = "Serial Bus", .subclass = pci_subclass_serialbus , .nsubclass = (sizeof((pci_subclass_serialbus)) / sizeof((pci_subclass_serialbus )[0])), }, | |||
1354 | CLASS(PCI_CLASS_WIRELESS, "Wireless",{ .class = 0x0d, .name = "Wireless", .subclass = pci_subclass_wireless , .nsubclass = (sizeof((pci_subclass_wireless)) / sizeof((pci_subclass_wireless )[0])), } | |||
1355 | pci_subclass_wireless){ .class = 0x0d, .name = "Wireless", .subclass = pci_subclass_wireless , .nsubclass = (sizeof((pci_subclass_wireless)) / sizeof((pci_subclass_wireless )[0])), }, | |||
1356 | CLASS(PCI_CLASS_I2O, "I2O",{ .class = 0x0e, .name = "I2O", .subclass = pci_subclass_i2o, .nsubclass = (sizeof((pci_subclass_i2o)) / sizeof((pci_subclass_i2o )[0])), } | |||
1357 | pci_subclass_i2o){ .class = 0x0e, .name = "I2O", .subclass = pci_subclass_i2o, .nsubclass = (sizeof((pci_subclass_i2o)) / sizeof((pci_subclass_i2o )[0])), }, | |||
1358 | CLASS(PCI_CLASS_SATCOM, "Satellite Comm",{ .class = 0x0f, .name = "Satellite Comm", .subclass = pci_subclass_satcom , .nsubclass = (sizeof((pci_subclass_satcom)) / sizeof((pci_subclass_satcom )[0])), } | |||
1359 | pci_subclass_satcom){ .class = 0x0f, .name = "Satellite Comm", .subclass = pci_subclass_satcom , .nsubclass = (sizeof((pci_subclass_satcom)) / sizeof((pci_subclass_satcom )[0])), }, | |||
1360 | CLASS(PCI_CLASS_CRYPTO, "Crypto",{ .class = 0x10, .name = "Crypto", .subclass = pci_subclass_crypto , .nsubclass = (sizeof((pci_subclass_crypto)) / sizeof((pci_subclass_crypto )[0])), } | |||
1361 | pci_subclass_crypto){ .class = 0x10, .name = "Crypto", .subclass = pci_subclass_crypto , .nsubclass = (sizeof((pci_subclass_crypto)) / sizeof((pci_subclass_crypto )[0])), }, | |||
1362 | CLASS(PCI_CLASS_DASP, "DASP",{ .class = 0x11, .name = "DASP", .subclass = pci_subclass_dasp , .nsubclass = (sizeof((pci_subclass_dasp)) / sizeof((pci_subclass_dasp )[0])), } | |||
1363 | pci_subclass_dasp){ .class = 0x11, .name = "DASP", .subclass = pci_subclass_dasp , .nsubclass = (sizeof((pci_subclass_dasp)) / sizeof((pci_subclass_dasp )[0])), }, | |||
1364 | CLASS(PCI_CLASS_ACCELERATOR, "Accelerator",{ .class = 0x12, .name = "Accelerator", .subclass = pci_subclass_accelerator , .nsubclass = (sizeof((pci_subclass_accelerator)) / sizeof(( pci_subclass_accelerator)[0])), } | |||
1365 | pci_subclass_accelerator){ .class = 0x12, .name = "Accelerator", .subclass = pci_subclass_accelerator , .nsubclass = (sizeof((pci_subclass_accelerator)) / sizeof(( pci_subclass_accelerator)[0])), }, | |||
1366 | CLASS(PCI_CLASS_INSTRUMENTATION, "Instrumentation",{ .class = 0x13, .name = "Instrumentation", .subclass = pci_subclass_instrumentation , .nsubclass = (sizeof((pci_subclass_instrumentation)) / sizeof ((pci_subclass_instrumentation)[0])), } | |||
1367 | pci_subclass_instrumentation){ .class = 0x13, .name = "Instrumentation", .subclass = pci_subclass_instrumentation , .nsubclass = (sizeof((pci_subclass_instrumentation)) / sizeof ((pci_subclass_instrumentation)[0])), }, | |||
1368 | }; | |||
1369 | ||||
1370 | static const struct pci_class * | |||
1371 | pci_class(pci_class_t class) | |||
1372 | { | |||
1373 | const struct pci_class *pc; | |||
1374 | size_t i; | |||
1375 | ||||
1376 | for (i = 0; i < nitems(pci_classes)(sizeof((pci_classes)) / sizeof((pci_classes)[0])); i++) { | |||
1377 | pc = &pci_classes[i]; | |||
1378 | if (pc->class == class) | |||
1379 | return (pc); | |||
1380 | } | |||
1381 | ||||
1382 | return (NULL((void *)0)); | |||
1383 | } | |||
1384 | ||||
1385 | static const struct pci_subclass * | |||
1386 | pci_subclass(const struct pci_class *pc, pci_subclass_t subclass) | |||
1387 | { | |||
1388 | const struct pci_subclass *ps; | |||
1389 | size_t i; | |||
1390 | ||||
1391 | for (i = 0; i < pc->nsubclass; i++) { | |||
1392 | ps = &pc->subclass[i]; | |||
1393 | if (ps->subclass == subclass) | |||
1394 | return (ps); | |||
1395 | } | |||
1396 | ||||
1397 | return (NULL((void *)0)); | |||
1398 | } | |||
1399 | ||||
1400 | static const char * | |||
1401 | pci_class_name(pci_class_t class) | |||
1402 | { | |||
1403 | const struct pci_class *pc; | |||
1404 | ||||
1405 | pc = pci_class(class); | |||
1406 | if (pc == NULL((void *)0)) | |||
1407 | return ("(unknown)"); | |||
1408 | ||||
1409 | return (pc->name); | |||
1410 | } | |||
1411 | ||||
1412 | static const char * | |||
1413 | pci_subclass_name(pci_class_t class, pci_subclass_t subclass) | |||
1414 | { | |||
1415 | const struct pci_class *pc; | |||
1416 | const struct pci_subclass *ps; | |||
1417 | ||||
1418 | pc = pci_class(class); | |||
1419 | if (pc == NULL((void *)0)) | |||
1420 | return ("(unknown)"); | |||
1421 | ||||
1422 | ps = pci_subclass(pc, subclass); | |||
1423 | if (ps == NULL((void *)0) || ps->name == NULL((void *)0)) | |||
1424 | return ("(unknown)"); | |||
1425 | ||||
1426 | return (ps->name); | |||
1427 | } |