File: | src/usr.sbin/pcidump/pcidump.c |
Warning: | line 760, column 10 Assigned value is garbage or undefined |
Press '?' to see keyboard shortcuts
Keyboard shortcuts:
1 | /* $OpenBSD: pcidump.c,v 1.68 2021/10/25 19:54:29 kn 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 & 4) | |||
532 | printf("8.0"); | |||
533 | else if (speed & 2) | |||
534 | printf("5.0"); | |||
535 | else if (speed & 1) | |||
536 | printf("2.5"); | |||
537 | else | |||
538 | printf("unknown (%d)", speed); | |||
539 | } | |||
540 | ||||
541 | void | |||
542 | dump_pcie_linkspeed(int bus, int dev, int func, uint8_t ptr) | |||
543 | { | |||
544 | u_int32_t dcap, dcsr; | |||
545 | u_int32_t lcap, sreg, lcap2 = 0, xcap; | |||
546 | u_int8_t cwidth, cspeed, swidth, sspeed; | |||
547 | ||||
548 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCAP0x04, &dcap) != 0) | |||
549 | return; | |||
550 | ||||
551 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_DCSR0x08, &dcsr) != 0) | |||
552 | return; | |||
553 | ||||
554 | printf("\t\tMax Payload Size: %u / %u bytes\n", | |||
555 | pcie_dcsr_mps(dcsr), pcie_dcap_mps(dcap)); | |||
556 | printf("\t\tMax Read Request Size: %u bytes\n", | |||
557 | pcie_dcsr_mrrs(dcsr)); | |||
558 | ||||
559 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_XCAP0x00, &xcap) != 0) | |||
560 | return; | |||
561 | ||||
562 | if (PCI_PCIE_XCAP_VER(xcap)(((xcap) >> 16) & 0x0f) >= 2) { | |||
563 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP20x2c, &lcap2) != 0) | |||
564 | lcap2 = 0; | |||
565 | else | |||
566 | cspeed = (lcap2 & 0x0e) >> 1; | |||
567 | } | |||
568 | ||||
569 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCAP0x0c, &lcap) != 0) | |||
570 | return; | |||
571 | if (lcap2 == 0) | |||
572 | cspeed = lcap & 0x0f; | |||
573 | ||||
574 | if (pci_read(bus, dev, func, ptr + PCI_PCIE_LCSR0x10, &sreg) != 0) | |||
575 | return; | |||
576 | sreg = sreg >> 16; | |||
577 | ||||
578 | cwidth = (lcap >> 4) & 0x3f; | |||
579 | if (cwidth == 0) | |||
580 | return; | |||
581 | ||||
582 | swidth = (sreg >> 4) & 0x3f; | |||
583 | sspeed = sreg & 0x0f; | |||
584 | ||||
585 | printf("\t\tLink Speed: "); | |||
586 | print_pcie_ls(sspeed); | |||
587 | printf(" / "); | |||
588 | print_pcie_ls(cspeed); | |||
589 | printf(" GT/s\n"); | |||
590 | ||||
591 | printf("\t\tLink Width: x%d / x%d\n", swidth, cwidth); | |||
592 | } | |||
593 | ||||
594 | void | |||
595 | dump_pcie_devserial(int bus, int dev, int func, u_int16_t ptr) | |||
596 | { | |||
597 | uint32_t lower, upper; | |||
598 | uint64_t serial; | |||
599 | ||||
600 | if ((pci_read(bus, dev, func, ptr + 8, &upper) != 0) || | |||
601 | (pci_read(bus, dev, func, ptr + 4, &lower) != 0)) | |||
602 | return; | |||
603 | ||||
604 | serial = ((uint64_t)upper << 32) | (uint64_t)lower; | |||
605 | ||||
606 | printf("\t\tSerial Number: %016llx\n", serial); | |||
607 | } | |||
608 | ||||
609 | void | |||
610 | dump_msi(int bus, int dev, int func, u_int8_t ptr) | |||
611 | { | |||
612 | u_int32_t reg; | |||
613 | ||||
614 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
615 | return; | |||
616 | ||||
617 | printf("\t\tEnabled: %s\n", reg & PCI_MSI_MC_MSIE0x00010000 ? "yes" : "no"); | |||
618 | } | |||
619 | ||||
620 | void | |||
621 | dump_msix(int bus, int dev, int func, u_int8_t ptr) | |||
622 | { | |||
623 | u_int32_t reg; | |||
624 | u_int32_t table; | |||
625 | ||||
626 | if ((pci_read(bus, dev, func, ptr, ®) != 0) || | |||
627 | (pci_read(bus, dev, func, ptr + PCI_MSIX_TABLE0x04, &table) != 0)) | |||
628 | return; | |||
629 | ||||
630 | printf("\t\tEnabled: %s; table size %d (BAR %d:%d)\n", | |||
631 | reg & PCI_MSIX_MC_MSIXE0x80000000 ? "yes" : "no", | |||
632 | PCI_MSIX_MC_TBLSZ(reg)(((reg) & 0x07ff0000) >> 16) + 1, | |||
633 | (table & PCI_MSIX_TABLE_BIR0x00000007), | |||
634 | (table & PCI_MSIX_TABLE_OFF~(0x00000007))); | |||
635 | } | |||
636 | ||||
637 | void | |||
638 | dump_pcie_enhanced_caplist(int bus, int dev, int func) | |||
639 | { | |||
640 | u_int32_t reg; | |||
641 | u_int32_t capidx; | |||
642 | u_int16_t ptr; | |||
643 | u_int16_t ecap; | |||
644 | ||||
645 | ptr = PCI_PCIE_ECAP0x100; | |||
646 | ||||
647 | do { | |||
648 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
649 | return; | |||
650 | ||||
651 | if (PCI_PCIE_ECAP_ID(reg)(((reg) & 0x0000ffff)) == 0xffff && | |||
652 | PCI_PCIE_ECAP_NEXT(reg)(((reg) >> 20) & 0xffc) == PCI_PCIE_ECAP_LAST0x0) | |||
653 | return; | |||
654 | ||||
655 | ecap = PCI_PCIE_ECAP_ID(reg)(((reg) & 0x0000ffff)); | |||
656 | if (ecap >= nitems(pci_enhanced_capnames)(sizeof((pci_enhanced_capnames)) / sizeof((pci_enhanced_capnames )[0]))) | |||
657 | capidx = 0; | |||
658 | else | |||
659 | capidx = ecap; | |||
660 | ||||
661 | printf("\t0x%04x: Enhanced Capability 0x%02x: ", ptr, ecap); | |||
662 | printf("%s\n", pci_enhanced_capnames[capidx]); | |||
663 | ||||
664 | switch (ecap) { | |||
665 | case 0x03: | |||
666 | dump_pcie_devserial(bus, dev, func, ptr); | |||
667 | break; | |||
668 | } | |||
669 | ||||
670 | ptr = PCI_PCIE_ECAP_NEXT(reg)(((reg) >> 20) & 0xffc); | |||
671 | ||||
672 | } while (ptr != PCI_PCIE_ECAP_LAST0x0); | |||
673 | } | |||
674 | ||||
675 | void | |||
676 | dump_caplist(int bus, int dev, int func, u_int8_t ptr) | |||
677 | { | |||
678 | u_int32_t reg; | |||
679 | u_int8_t cap; | |||
680 | ||||
681 | if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG0x04, ®) != 0) | |||
682 | return; | |||
683 | if (!(reg & PCI_STATUS_CAPLIST_SUPPORT0x00100000)) | |||
684 | return; | |||
685 | ||||
686 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
687 | return; | |||
688 | ptr = PCI_CAPLIST_PTR(reg)((reg) & 0xff); | |||
689 | while (ptr != 0) { | |||
690 | if (pci_read(bus, dev, func, ptr, ®) != 0) | |||
691 | return; | |||
692 | cap = PCI_CAPLIST_CAP(reg)((reg) & 0xff); | |||
693 | printf("\t0x%04x: Capability 0x%02x: ", ptr, cap); | |||
694 | if (cap >= nitems(pci_capnames)(sizeof((pci_capnames)) / sizeof((pci_capnames)[0]))) | |||
695 | cap = 0; | |||
696 | printf("%s\n", pci_capnames[cap]); | |||
697 | switch (cap) { | |||
698 | case PCI_CAP_PWRMGMT0x01: | |||
699 | dump_pci_powerstate(bus, dev, func, ptr); | |||
700 | break; | |||
701 | case PCI_CAP_VPD0x03: | |||
702 | dump_vpd(bus, dev, func); | |||
703 | break; | |||
704 | case PCI_CAP_PCIEXPRESS0x10: | |||
705 | dump_pcie_linkspeed(bus, dev, func, ptr); | |||
706 | dump_pcie_enhanced_caplist(bus, dev, func); | |||
707 | break; | |||
708 | case PCI_CAP_MSI0x05: | |||
709 | dump_msi(bus, dev,func, ptr); | |||
710 | break; | |||
711 | case PCI_CAP_MSIX0x11: | |||
712 | dump_msix(bus, dev, func, ptr); | |||
713 | break; | |||
714 | } | |||
715 | ptr = PCI_CAPLIST_NEXT(reg)(((reg) >> 8) & 0xff); | |||
716 | } | |||
717 | } | |||
718 | ||||
719 | void | |||
720 | dump_bars(int bus, int dev, int func, int end) | |||
721 | { | |||
722 | const char *memtype; | |||
723 | u_int64_t mem; | |||
724 | u_int64_t mask; | |||
725 | u_int32_t reg, reg1; | |||
726 | int bar; | |||
727 | ||||
728 | for (bar = PCI_MAPREG_START0x10; bar < end; bar += 0x4) { | |||
729 | if (pci_read(bus, dev, func, bar, ®) != 0 || | |||
730 | pci_readmask(bus, dev, func, bar, ®1) != 0) | |||
731 | warn("unable to read PCI_MAPREG 0x%02x", bar); | |||
732 | ||||
733 | printf("\t0x%04x: BAR ", bar); | |||
734 | ||||
735 | if (reg == 0 && reg1 == 0) { | |||
736 | printf("empty (%08x)\n", reg); | |||
737 | continue; | |||
738 | } | |||
739 | ||||
740 | switch (PCI_MAPREG_TYPE(reg)((reg) & 0x00000001)) { | |||
741 | case PCI_MAPREG_TYPE_MEM0x00000000: | |||
742 | printf("mem "); | |||
743 | if (PCI_MAPREG_MEM_PREFETCHABLE(reg)(((reg) & 0x00000008) != 0)) | |||
744 | printf("prefetchable "); | |||
745 | ||||
746 | memtype = "32bit 1m"; | |||
747 | switch (PCI_MAPREG_MEM_TYPE(reg)((reg) & 0x00000006)) { | |||
748 | case PCI_MAPREG_MEM_TYPE_32BIT0x00000000: | |||
749 | memtype = "32bit"; | |||
750 | case PCI_MAPREG_MEM_TYPE_32BIT_1M0x00000002: | |||
751 | printf("%s ", memtype); | |||
752 | ||||
753 | printf("addr: 0x%08x/0x%08x\n", | |||
754 | PCI_MAPREG_MEM_ADDR(reg)((reg) & 0xfffffff0), | |||
755 | PCI_MAPREG_MEM_SIZE(reg1)(((reg1) & 0xfffffff0) & -((reg1) & 0xfffffff0))); | |||
756 | ||||
757 | break; | |||
758 | case PCI_MAPREG_MEM_TYPE_64BIT0x00000004: | |||
759 | mem = reg; | |||
760 | mask = reg1; | |||
| ||||
761 | bar += 0x04; | |||
762 | if (pci_read(bus, dev, func, bar, ®) != 0 || | |||
763 | pci_readmask(bus, dev, func, bar, ®1) != 0) | |||
764 | warn("unable to read 0x%02x", bar); | |||
765 | ||||
766 | mem |= (u_int64_t)reg << 32; | |||
767 | mask |= (u_int64_t)reg1 << 32; | |||
768 | ||||
769 | printf("64bit addr: 0x%016llx/0x%08llx\n", | |||
770 | PCI_MAPREG_MEM64_ADDR(mem)((mem) & 0xfffffffffffffff0ULL), | |||
771 | PCI_MAPREG_MEM64_SIZE(mask)(((mask) & 0xfffffffffffffff0ULL) & -((mask) & 0xfffffffffffffff0ULL ))); | |||
772 | ||||
773 | break; | |||
774 | } | |||
775 | break; | |||
776 | ||||
777 | case PCI_MAPREG_TYPE_IO0x00000001: | |||
778 | printf("io addr: 0x%08x/0x%04x\n", | |||
779 | PCI_MAPREG_IO_ADDR(reg)((reg) & 0xfffffffe), | |||
780 | PCI_MAPREG_IO_SIZE(reg1)(((reg1) & 0xfffffffe) & -((reg1) & 0xfffffffe))); | |||
781 | break; | |||
782 | } | |||
783 | } | |||
784 | } | |||
785 | ||||
786 | void | |||
787 | dump_type0(int bus, int dev, int func) | |||
788 | { | |||
789 | u_int32_t reg; | |||
790 | ||||
791 | dump_bars(bus, dev, func, PCI_MAPREG_END0x28); | |||
792 | ||||
793 | if (pci_read(bus, dev, func, PCI_CARDBUS_CIS_REG0x28, ®) != 0) | |||
794 | warn("unable to read PCI_CARDBUS_CIS_REG"); | |||
795 | printf("\t0x%04x: Cardbus CIS: %08x\n", PCI_CARDBUS_CIS_REG0x28, reg); | |||
796 | ||||
797 | if (pci_read(bus, dev, func, PCI_SUBSYS_ID_REG0x2c, ®) != 0) | |||
798 | warn("unable to read PCI_SUBSYS_ID_REG"); | |||
799 | printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n", | |||
800 | PCI_SUBSYS_ID_REG0x2c, PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
801 | ||||
802 | if (pci_read(bus, dev, func, PCI_ROM_REG0x30, ®) != 0) | |||
803 | warn("unable to read PCI_ROM_REG"); | |||
804 | printf("\t0x%04x: Expansion ROM Base Address: %08x\n", | |||
805 | PCI_ROM_REG0x30, reg); | |||
806 | ||||
807 | if (pci_read(bus, dev, func, 0x38, ®) != 0) | |||
808 | warn("unable to read 0x38 (reserved)"); | |||
809 | printf("\t0x%04x: %08x\n", 0x38, reg); | |||
810 | ||||
811 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
812 | warn("unable to read PCI_INTERRUPT_REG"); | |||
813 | printf("\t0x%04x: Interrupt Pin: %02x Line: %02x Min Gnt: %02x" | |||
814 | " Max Lat: %02x\n", PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
815 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), PCI_MIN_GNT(reg)(((reg) >> 16) & 0xff), PCI_MAX_LAT(reg)(((reg) >> 24) & 0xff)); | |||
816 | } | |||
817 | ||||
818 | void | |||
819 | dump_type1(int bus, int dev, int func) | |||
820 | { | |||
821 | u_int32_t reg; | |||
822 | ||||
823 | dump_bars(bus, dev, func, PCI_MAPREG_PPB_END0x18); | |||
824 | ||||
825 | if (pci_read(bus, dev, func, PCI_PRIBUS_10x18, ®) != 0) | |||
826 | warn("unable to read PCI_PRIBUS_1"); | |||
827 | printf("\t0x%04x: Primary Bus: %d, Secondary Bus: %d, " | |||
828 | "Subordinate Bus: %d,\n\t\tSecondary Latency Timer: %02x\n", | |||
829 | PCI_PRIBUS_10x18, (reg >> 0) & 0xff, (reg >> 8) & 0xff, | |||
830 | (reg >> 16) & 0xff, (reg >> 24) & 0xff); | |||
831 | ||||
832 | if (pci_read(bus, dev, func, PCI_IOBASEL_10x1c, ®) != 0) | |||
833 | warn("unable to read PCI_IOBASEL_1"); | |||
834 | printf("\t0x%04x: I/O Base: %02x, I/O Limit: %02x, " | |||
835 | "Secondary Status: %04x\n", PCI_IOBASEL_10x1c, (reg >> 0 ) & 0xff, | |||
836 | (reg >> 8) & 0xff, (reg >> 16) & 0xffff); | |||
837 | ||||
838 | if (pci_read(bus, dev, func, PCI_MEMBASE_10x20, ®) != 0) | |||
839 | warn("unable to read PCI_MEMBASE_1"); | |||
840 | printf("\t0x%04x: Memory Base: %04x, Memory Limit: %04x\n", | |||
841 | PCI_MEMBASE_10x20, (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
842 | ||||
843 | if (pci_read(bus, dev, func, PCI_PMBASEL_10x24, ®) != 0) | |||
844 | warn("unable to read PCI_PMBASEL_1"); | |||
845 | printf("\t0x%04x: Prefetch Memory Base: %04x, " | |||
846 | "Prefetch Memory Limit: %04x\n", PCI_PMBASEL_10x24, | |||
847 | (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
848 | ||||
849 | #undef PCI_PMBASEH_10x28 | |||
850 | #define PCI_PMBASEH_10x28 0x28 | |||
851 | if (pci_read(bus, dev, func, PCI_PMBASEH_10x28, ®) != 0) | |||
852 | warn("unable to read PCI_PMBASEH_1"); | |||
853 | printf("\t0x%04x: Prefetch Memory Base Upper 32 Bits: %08x\n", | |||
854 | PCI_PMBASEH_10x28, reg); | |||
855 | ||||
856 | #undef PCI_PMLIMITH_10x2c | |||
857 | #define PCI_PMLIMITH_10x2c 0x2c | |||
858 | if (pci_read(bus, dev, func, PCI_PMLIMITH_10x2c, ®) != 0) | |||
859 | warn("unable to read PCI_PMLIMITH_1"); | |||
860 | printf("\t0x%04x: Prefetch Memory Limit Upper 32 Bits: %08x\n", | |||
861 | PCI_PMLIMITH_10x2c, reg); | |||
862 | ||||
863 | #undef PCI_IOBASEH_10x30 | |||
864 | #define PCI_IOBASEH_10x30 0x30 | |||
865 | if (pci_read(bus, dev, func, PCI_IOBASEH_10x30, ®) != 0) | |||
866 | warn("unable to read PCI_IOBASEH_1"); | |||
867 | printf("\t0x%04x: I/O Base Upper 16 Bits: %04x, " | |||
868 | "I/O Limit Upper 16 Bits: %04x\n", PCI_IOBASEH_10x30, | |||
869 | (reg >> 0) & 0xffff, (reg >> 16) & 0xffff); | |||
870 | ||||
871 | #define PCI_PPB_ROM_REG0x38 0x38 | |||
872 | if (pci_read(bus, dev, func, PCI_PPB_ROM_REG0x38, ®) != 0) | |||
873 | warn("unable to read PCI_PPB_ROM_REG"); | |||
874 | printf("\t0x%04x: Expansion ROM Base Address: %08x\n", | |||
875 | PCI_PPB_ROM_REG0x38, reg); | |||
876 | ||||
877 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
878 | warn("unable to read PCI_INTERRUPT_REG"); | |||
879 | printf("\t0x%04x: Interrupt Pin: %02x, Line: %02x, " | |||
880 | "Bridge Control: %04x\n", | |||
881 | PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
882 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), reg >> 16); | |||
883 | } | |||
884 | ||||
885 | void | |||
886 | dump_type2(int bus, int dev, int func) | |||
887 | { | |||
888 | u_int32_t reg; | |||
889 | ||||
890 | if (pci_read(bus, dev, func, PCI_MAPREG_START0x10, ®) != 0) | |||
891 | warn("unable to read PCI_MAPREG\n"); | |||
892 | printf("\t0x%04x: Cardbus Control Registers Base Address: %08x\n", | |||
893 | PCI_MAPREG_START0x10, reg); | |||
894 | ||||
895 | if (pci_read(bus, dev, func, PCI_PRIBUS_20x18, ®) != 0) | |||
896 | warn("unable to read PCI_PRIBUS_2"); | |||
897 | printf("\t0x%04x: Primary Bus: %d Cardbus Bus: %d " | |||
898 | "Subordinate Bus: %d \n\t Cardbus Latency Timer: %02x\n", | |||
899 | PCI_PRIBUS_20x18, (reg >> 0) & 0xff, (reg >> 8) & 0xff, | |||
900 | (reg >> 16) & 0xff, (reg >> 24) & 0xff); | |||
901 | ||||
902 | if (pci_read(bus, dev, func, PCI_MEMBASE0_20x1c, ®) != 0) | |||
903 | warn("unable to read PCI_MEMBASE0_2\n"); | |||
904 | printf("\t0x%04x: Memory Base 0: %08x\n", PCI_MEMBASE0_20x1c, reg); | |||
905 | ||||
906 | if (pci_read(bus, dev, func, PCI_MEMLIMIT0_20x20, ®) != 0) | |||
907 | warn("unable to read PCI_MEMLIMIT0_2\n"); | |||
908 | printf("\t0x%04x: Memory Limit 0: %08x\n", PCI_MEMLIMIT0_20x20, reg); | |||
909 | ||||
910 | if (pci_read(bus, dev, func, PCI_MEMBASE1_20x24, ®) != 0) | |||
911 | warn("unable to read PCI_MEMBASE1_2\n"); | |||
912 | printf("\t0x%04x: Memory Base 1: %08x\n", PCI_MEMBASE1_20x24, reg); | |||
913 | ||||
914 | if (pci_read(bus, dev, func, PCI_MEMLIMIT1_20x28, ®) != 0) | |||
915 | warn("unable to read PCI_MEMLIMIT1_2\n"); | |||
916 | printf("\t0x%04x: Memory Limit 1: %08x\n", PCI_MEMLIMIT1_20x28, reg); | |||
917 | ||||
918 | if (pci_read(bus, dev, func, PCI_IOBASE0_20x2c, ®) != 0) | |||
919 | warn("unable to read PCI_IOBASE0_2\n"); | |||
920 | printf("\t0x%04x: I/O Base 0: %08x\n", PCI_IOBASE0_20x2c, reg); | |||
921 | ||||
922 | if (pci_read(bus, dev, func, PCI_IOLIMIT0_20x30, ®) != 0) | |||
923 | warn("unable to read PCI_IOLIMIT0_2\n"); | |||
924 | printf("\t0x%04x: I/O Limit 0: %08x\n", PCI_IOLIMIT0_20x30, reg); | |||
925 | ||||
926 | if (pci_read(bus, dev, func, PCI_IOBASE1_20x34, ®) != 0) | |||
927 | warn("unable to read PCI_IOBASE1_2\n"); | |||
928 | printf("\t0x%04x: I/O Base 1: %08x\n", PCI_IOBASE1_20x34, reg); | |||
929 | ||||
930 | if (pci_read(bus, dev, func, PCI_IOLIMIT1_20x38, ®) != 0) | |||
931 | warn("unable to read PCI_IOLIMIT1_2\n"); | |||
932 | printf("\t0x%04x: I/O Limit 1: %08x\n", PCI_IOLIMIT1_20x38, reg); | |||
933 | ||||
934 | if (pci_read(bus, dev, func, PCI_INTERRUPT_REG0x3c, ®) != 0) | |||
935 | warn("unable to read PCI_INTERRUPT_REG"); | |||
936 | printf("\t0x%04x: Interrupt Pin: %02x Line: %02x " | |||
937 | "Bridge Control: %04x\n", | |||
938 | PCI_INTERRUPT_REG0x3c, PCI_INTERRUPT_PIN(reg)(((reg) >> 8) & 0xff), | |||
939 | PCI_INTERRUPT_LINE(reg)(((reg) >> 0) & 0xff), reg >> 16); | |||
940 | ||||
941 | if (pci_read(bus, dev, func, PCI_SUBVEND_20x40, ®) != 0) | |||
942 | warn("unable to read PCI_SUBVEND_2"); | |||
943 | printf("\t0x%04x: Subsystem Vendor ID: %04x Product ID: %04x\n", | |||
944 | PCI_SUBVEND_20x40, PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
945 | ||||
946 | if (pci_read(bus, dev, func, PCI_PCCARDIF_20x44, ®) != 0) | |||
947 | warn("unable to read PCI_PCCARDIF_2\n"); | |||
948 | printf("\t0x%04x: 16-bit Legacy Mode Base Address: %08x\n", | |||
949 | PCI_PCCARDIF_20x44, reg); | |||
950 | } | |||
951 | ||||
952 | void | |||
953 | dump(int bus, int dev, int func) | |||
954 | { | |||
955 | u_int32_t reg; | |||
956 | u_int8_t capptr = PCI_CAPLISTPTR_REG0x34; | |||
957 | pci_class_t class; | |||
958 | pci_subclass_t subclass; | |||
959 | ||||
960 | if (pci_read(bus, dev, func, PCI_ID_REG0x00, ®) != 0) | |||
961 | warn("unable to read PCI_ID_REG"); | |||
962 | printf("\t0x%04x: Vendor ID: %04x, Product ID: %04x\n", PCI_ID_REG0x00, | |||
963 | PCI_VENDOR(reg)(((reg) >> 0) & 0xffff), PCI_PRODUCT(reg)(((reg) >> 16) & 0xffff)); | |||
964 | ||||
965 | if (pci_read(bus, dev, func, PCI_COMMAND_STATUS_REG0x04, ®) != 0) | |||
966 | warn("unable to read PCI_COMMAND_STATUS_REG"); | |||
967 | printf("\t0x%04x: Command: %04x, Status: %04x\n", | |||
968 | PCI_COMMAND_STATUS_REG0x04, reg & 0xffff, (reg >> 16) & 0xffff); | |||
969 | ||||
970 | if (pci_read(bus, dev, func, PCI_CLASS_REG0x08, ®) != 0) | |||
971 | warn("unable to read PCI_CLASS_REG"); | |||
972 | class = PCI_CLASS(reg)(((reg) >> 24) & 0xff); | |||
973 | subclass = PCI_SUBCLASS(reg)(((reg) >> 16) & 0xff); | |||
974 | printf("\t0x%04x:\tClass: %02x %s,", PCI_CLASS_REG0x08, class, | |||
975 | pci_class_name(class)); | |||
976 | printf(" Subclass: %02x %s,", subclass, | |||
977 | pci_subclass_name(class, subclass)); | |||
978 | printf("\n\t\tInterface: %02x, Revision: %02x\n", | |||
979 | PCI_INTERFACE(reg)(((reg) >> 8) & 0xff), PCI_REVISION(reg)(((reg) >> 0) & 0xff)); | |||
980 | ||||
981 | if (pci_read(bus, dev, func, PCI_BHLC_REG0x0c, ®) != 0) | |||
982 | warn("unable to read PCI_BHLC_REG"); | |||
983 | printf("\t0x%04x: BIST: %02x, Header Type: %02x, " | |||
984 | "Latency Timer: %02x,\n\t\tCache Line Size: %02x\n", PCI_BHLC_REG0x0c, | |||
985 | PCI_BIST(reg)(((reg) >> 24) & 0xff), PCI_HDRTYPE(reg)(((reg) >> 16) & 0xff), | |||
986 | PCI_LATTIMER(reg)(((reg) >> 8) & 0xff), PCI_CACHELINE(reg)(((reg) >> 0) & 0xff)); | |||
987 | ||||
988 | switch (PCI_HDRTYPE_TYPE(reg)((((reg) >> 16) & 0xff) & 0x7f)) { | |||
989 | case 2: | |||
990 | dump_type2(bus, dev, func); | |||
991 | capptr = PCI_CARDBUS_CAPLISTPTR_REG0x14; | |||
992 | break; | |||
993 | case 1: | |||
994 | dump_type1(bus, dev, func); | |||
995 | break; | |||
996 | case 0: | |||
997 | dump_type0(bus, dev, func); | |||
998 | break; | |||
999 | default: | |||
1000 | break; | |||
1001 | } | |||
1002 | dump_caplist(bus, dev, func, capptr); | |||
1003 | } | |||
1004 | ||||
1005 | void | |||
1006 | hexdump(int bus, int dev, int func, int size) | |||
1007 | { | |||
1008 | u_int32_t reg; | |||
1009 | int i; | |||
1010 | ||||
1011 | for (i = 0; i < size; i += 4) { | |||
1012 | if (pci_read(bus, dev, func, i, ®) != 0) { | |||
1013 | if (errno(*__errno()) == EINVAL22) | |||
1014 | return; | |||
1015 | warn("unable to read 0x%02x", i); | |||
1016 | } | |||
1017 | ||||
1018 | if ((i % 16) == 0) | |||
1019 | printf("\t0x%04x:", i); | |||
1020 | printf(" %08x", reg); | |||
1021 | ||||
1022 | if ((i % 16) == 12) | |||
1023 | printf("\n"); | |||
1024 | } | |||
1025 | } | |||
1026 | ||||
1027 | int | |||
1028 | pci_nfuncs(int bus, int dev) | |||
1029 | { | |||
1030 | u_int32_t hdr; | |||
1031 | ||||
1032 | if (pci_read(bus, dev, 0, PCI_BHLC_REG0x0c, &hdr) != 0) | |||
1033 | return (-1); | |||
1034 | ||||
1035 | return (PCI_HDRTYPE_MULTIFN(hdr)(((((hdr) >> 16) & 0xff) & 0x80) != 0) ? 8 : 1); | |||
1036 | } | |||
1037 | ||||
1038 | int | |||
1039 | pci_read(int bus, int dev, int func, u_int32_t reg, u_int32_t *val) | |||
1040 | { | |||
1041 | struct pci_io io; | |||
1042 | int rv; | |||
1043 | ||||
1044 | bzero(&io, sizeof(io)); | |||
1045 | io.pi_sel.pc_bus = bus; | |||
1046 | io.pi_sel.pc_dev = dev; | |||
1047 | io.pi_sel.pc_func = func; | |||
1048 | io.pi_reg = reg; | |||
1049 | io.pi_width = 4; | |||
1050 | ||||
1051 | rv = ioctl(pcifd, PCIOCREAD(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_io) & 0x1fff) << 16) | ((('p')) << 8) | ((2))), &io); | |||
1052 | if (rv != 0) | |||
1053 | return (rv); | |||
1054 | ||||
1055 | *val = io.pi_data; | |||
1056 | ||||
1057 | return (0); | |||
1058 | } | |||
1059 | ||||
1060 | int | |||
1061 | pci_readmask(int bus, int dev, int func, u_int32_t reg, u_int32_t *val) | |||
1062 | { | |||
1063 | struct pci_io io; | |||
1064 | int rv; | |||
1065 | ||||
1066 | bzero(&io, sizeof(io)); | |||
1067 | io.pi_sel.pc_bus = bus; | |||
1068 | io.pi_sel.pc_dev = dev; | |||
1069 | io.pi_sel.pc_func = func; | |||
1070 | io.pi_reg = reg; | |||
1071 | io.pi_width = 4; | |||
1072 | ||||
1073 | rv = ioctl(pcifd, PCIOCREADMASK(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_io) & 0x1fff) << 16) | ((('p')) << 8) | ((8))), &io); | |||
1074 | if (rv != 0) | |||
1075 | return (rv); | |||
1076 | ||||
1077 | *val = io.pi_data; | |||
1078 | ||||
1079 | return (0); | |||
1080 | } | |||
1081 | ||||
1082 | int | |||
1083 | dump_rom(int bus, int dev, int func) | |||
1084 | { | |||
1085 | struct pci_rom rom; | |||
1086 | u_int32_t cr, addr; | |||
1087 | ||||
1088 | if (pci_read(bus, dev, func, PCI_ROM_REG0x30, &addr) != 0 || | |||
1089 | pci_read(bus, dev, func, PCI_CLASS_REG0x08, &cr) != 0) | |||
1090 | return (errno(*__errno())); | |||
1091 | ||||
1092 | if (addr == 0 && PCI_CLASS(cr)(((cr) >> 24) & 0xff) == PCI_CLASS_DISPLAY0x03 && | |||
1093 | PCI_SUBCLASS(cr)(((cr) >> 16) & 0xff) == PCI_SUBCLASS_DISPLAY_VGA0x00) | |||
1094 | return dump_vga_bios(); | |||
1095 | ||||
1096 | bzero(&rom, sizeof(rom)); | |||
1097 | rom.pr_sel.pc_bus = bus; | |||
1098 | rom.pr_sel.pc_dev = dev; | |||
1099 | rom.pr_sel.pc_func = func; | |||
1100 | if (ioctl(pcifd, PCIOCGETROMLEN(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_rom) & 0x1fff) << 16) | ((('p')) << 8) | ((4))), &rom) == -1) | |||
1101 | return (errno(*__errno())); | |||
1102 | ||||
1103 | rom.pr_rom = malloc(rom.pr_romlen); | |||
1104 | if (rom.pr_rom == NULL((void *)0)) | |||
1105 | return (ENOMEM12); | |||
1106 | ||||
1107 | if (ioctl(pcifd, PCIOCGETROM(((unsigned long)0x80000000|(unsigned long)0x40000000) | ((sizeof (struct pci_rom) & 0x1fff) << 16) | ((('p')) << 8) | ((5))), &rom) == -1) | |||
1108 | return (errno(*__errno())); | |||
1109 | ||||
1110 | if (write(romfd, rom.pr_rom, rom.pr_romlen) == -1) | |||
1111 | return (errno(*__errno())); | |||
1112 | ||||
1113 | return (0); | |||
1114 | } | |||
1115 | ||||
1116 | #define VGA_BIOS_ADDR0xc0000 0xc0000 | |||
1117 | #define VGA_BIOS_LEN0x10000 0x10000 | |||
1118 | ||||
1119 | int | |||
1120 | dump_vga_bios(void) | |||
1121 | { | |||
1122 | #if defined(__amd64__1) || defined(__i386__) | |||
1123 | void *bios; | |||
1124 | int fd; | |||
1125 | ||||
1126 | fd = open(_PATH_MEM"/dev/mem", O_RDONLY0x0000); | |||
1127 | if (fd == -1) | |||
1128 | err(1, "%s", _PATH_MEM"/dev/mem"); | |||
1129 | ||||
1130 | bios = malloc(VGA_BIOS_LEN0x10000); | |||
1131 | if (bios == NULL((void *)0)) | |||
1132 | return (ENOMEM12); | |||
1133 | ||||
1134 | if (pread(fd, bios, VGA_BIOS_LEN0x10000, VGA_BIOS_ADDR0xc0000) == -1) | |||
1135 | err(1, "%s", _PATH_MEM"/dev/mem"); | |||
1136 | ||||
1137 | if (write(romfd, bios, VGA_BIOS_LEN0x10000) == -1) { | |||
1138 | free(bios); | |||
1139 | return (errno(*__errno())); | |||
1140 | } | |||
1141 | ||||
1142 | free(bios); | |||
1143 | ||||
1144 | return (0); | |||
1145 | #else | |||
1146 | return (ENODEV19); | |||
1147 | #endif | |||
1148 | } | |||
1149 | ||||
1150 | struct pci_subclass { | |||
1151 | pci_subclass_t subclass; | |||
1152 | const char *name; | |||
1153 | }; | |||
1154 | ||||
1155 | struct pci_class { | |||
1156 | pci_class_t class; | |||
1157 | const char *name; | |||
1158 | const struct pci_subclass | |||
1159 | *subclass; | |||
1160 | size_t nsubclass; | |||
1161 | }; | |||
1162 | ||||
1163 | static const struct pci_subclass pci_subclass_prehistoric[] = { | |||
1164 | { PCI_SUBCLASS_PREHISTORIC_MISC0x00, "Miscellaneous" }, | |||
1165 | { PCI_SUBCLASS_PREHISTORIC_VGA0x01, "VGA" }, | |||
1166 | }; | |||
1167 | ||||
1168 | static const struct pci_subclass pci_subclass_mass_storage[] = { | |||
1169 | { PCI_SUBCLASS_MASS_STORAGE_SCSI0x00, "SCSI" }, | |||
1170 | { PCI_SUBCLASS_MASS_STORAGE_IDE0x01, "IDE" }, | |||
1171 | { PCI_SUBCLASS_MASS_STORAGE_FLOPPY0x02, "Floppy" }, | |||
1172 | { PCI_SUBCLASS_MASS_STORAGE_IPI0x03, "IPI" }, | |||
1173 | { PCI_SUBCLASS_MASS_STORAGE_RAID0x04, "RAID" }, | |||
1174 | { PCI_SUBCLASS_MASS_STORAGE_ATA0x05, "ATA" }, | |||
1175 | { PCI_SUBCLASS_MASS_STORAGE_SATA0x06, "SATA" }, | |||
1176 | { PCI_SUBCLASS_MASS_STORAGE_SAS0x07, "SAS" }, | |||
1177 | { PCI_SUBCLASS_MASS_STORAGE_UFS0x09, "UFS" }, | |||
1178 | { PCI_SUBCLASS_MASS_STORAGE_NVM0x08, "NVM" }, | |||
1179 | { PCI_SUBCLASS_MASS_STORAGE_MISC0x80, "Miscellaneous" }, | |||
1180 | }; | |||
1181 | ||||
1182 | static const struct pci_subclass pci_subclass_network[] = { | |||
1183 | { PCI_SUBCLASS_NETWORK_ETHERNET0x00, "Ethernet" }, | |||
1184 | { PCI_SUBCLASS_NETWORK_TOKENRING0x01, "Token Ring" }, | |||
1185 | { PCI_SUBCLASS_NETWORK_FDDI0x02, "FDDI" }, | |||
1186 | { PCI_SUBCLASS_NETWORK_ATM0x03, "ATM" }, | |||
1187 | { PCI_SUBCLASS_NETWORK_ISDN0x04, "ISDN" }, | |||
1188 | { PCI_SUBCLASS_NETWORK_WORLDFIP0x05, "WorldFip" }, | |||
1189 | { PCI_SUBCLASS_NETWORK_PCIMGMULTICOMP0x06, "PCMIG Multi Computing" }, | |||
1190 | { PCI_SUBCLASS_NETWORK_INFINIBAND0x07, "InfiniBand" }, | |||
1191 | { PCI_SUBCLASS_NETWORK_MISC0x80, "Miscellaneous" }, | |||
1192 | }; | |||
1193 | ||||
1194 | static const struct pci_subclass pci_subclass_display[] = { | |||
1195 | { PCI_SUBCLASS_DISPLAY_VGA0x00, "VGA" }, | |||
1196 | { PCI_SUBCLASS_DISPLAY_XGA0x01, "XGA" }, | |||
1197 | { PCI_SUBCLASS_DISPLAY_3D0x02, "3D" }, | |||
1198 | { PCI_SUBCLASS_DISPLAY_MISC0x80, "Miscellaneous" }, | |||
1199 | }; | |||
1200 | ||||
1201 | static const struct pci_subclass pci_subclass_multimedia[] = { | |||
1202 | { PCI_SUBCLASS_MULTIMEDIA_VIDEO0x00, "Video" }, | |||
1203 | { PCI_SUBCLASS_MULTIMEDIA_AUDIO0x01, "Audio" }, | |||
1204 | { PCI_SUBCLASS_MULTIMEDIA_TELEPHONY0x02, "Telephony" }, | |||
1205 | { PCI_SUBCLASS_MULTIMEDIA_HDAUDIO0x03, "HD Audio" }, | |||
1206 | { PCI_SUBCLASS_MULTIMEDIA_MISC0x80, "Miscellaneous" }, | |||
1207 | }; | |||
1208 | ||||
1209 | static const struct pci_subclass pci_subclass_memory[] = { | |||
1210 | { PCI_SUBCLASS_MEMORY_RAM0x00, "RAM" }, | |||
1211 | { PCI_SUBCLASS_MEMORY_FLASH0x01, "Flash" }, | |||
1212 | { PCI_SUBCLASS_MEMORY_MISC0x80, "Miscellaneous" }, | |||
1213 | }; | |||
1214 | ||||
1215 | static const struct pci_subclass pci_subclass_bridge[] = { | |||
1216 | { PCI_SUBCLASS_BRIDGE_HOST0x00, "Host" }, | |||
1217 | { PCI_SUBCLASS_BRIDGE_ISA0x01, "ISA" }, | |||
1218 | { PCI_SUBCLASS_BRIDGE_EISA0x02, "EISA" }, | |||
1219 | { PCI_SUBCLASS_BRIDGE_MC0x03, "MicroChannel" }, | |||
1220 | { PCI_SUBCLASS_BRIDGE_PCI0x04, "PCI" }, | |||
1221 | { PCI_SUBCLASS_BRIDGE_PCMCIA0x05, "PCMCIA" }, | |||
1222 | { PCI_SUBCLASS_BRIDGE_NUBUS0x06, "NuBus" }, | |||
1223 | { PCI_SUBCLASS_BRIDGE_RACEWAY0x08, "RACEway" }, | |||
1224 | { PCI_SUBCLASS_BRIDGE_STPCI0x09, "Semi-transparent PCI" }, | |||
1225 | { PCI_SUBCLASS_BRIDGE_INFINIBAND0x0a, "InfiniBand" }, | |||
1226 | { PCI_SUBCLASS_BRIDGE_MISC0x80, "Miscellaneous" }, | |||
1227 | { PCI_SUBCLASS_BRIDGE_AS0x0b, "advanced switching" }, | |||
1228 | }; | |||
1229 | ||||
1230 | static const struct pci_subclass pci_subclass_communications[] = { | |||
1231 | { PCI_SUBCLASS_COMMUNICATIONS_SERIAL0x00, "Serial" }, | |||
1232 | { PCI_SUBCLASS_COMMUNICATIONS_PARALLEL0x01, "Parallel" }, | |||
1233 | { PCI_SUBCLASS_COMMUNICATIONS_MPSERIAL0x02, "Multi-port Serial" }, | |||
1234 | { PCI_SUBCLASS_COMMUNICATIONS_MODEM0x03, "Modem" }, | |||
1235 | { PCI_SUBCLASS_COMMUNICATIONS_GPIB0x04, "GPIB" }, | |||
1236 | { PCI_SUBCLASS_COMMUNICATIONS_SMARTCARD0x05, | |||
1237 | "Smartcard" }, | |||
1238 | { PCI_SUBCLASS_COMMUNICATIONS_MISC0x80, "Miscellaneous" }, | |||
1239 | }; | |||
1240 | ||||
1241 | static const struct pci_subclass pci_subclass_system[] = { | |||
1242 | { PCI_SUBCLASS_SYSTEM_PIC0x00, "Interrupt" }, | |||
1243 | { PCI_SUBCLASS_SYSTEM_DMA0x01, "8237 DMA" }, | |||
1244 | { PCI_SUBCLASS_SYSTEM_TIMER0x02, "8254 Timer" }, | |||
1245 | { PCI_SUBCLASS_SYSTEM_RTC0x03, "RTC" }, | |||
1246 | { PCI_SUBCLASS_SYSTEM_SDHC0x05, "SDHC" }, | |||
1247 | { PCI_SUBCLASS_SYSTEM_IOMMU0x06, "IOMMU" }, | |||
1248 | { PCI_SUBCLASS_SYSTEM_ROOTCOMPEVENT0x07, "Root Complex Event" }, | |||
1249 | { PCI_SUBCLASS_SYSTEM_MISC0x80, "Miscellaneous" }, | |||
1250 | }; | |||
1251 | ||||
1252 | static const struct pci_subclass pci_subclass_input[] = { | |||
1253 | { PCI_SUBCLASS_INPUT_KEYBOARD0x00, "Keyboard" }, | |||
1254 | { PCI_SUBCLASS_INPUT_DIGITIZER0x01, "Digitizer" }, | |||
1255 | { PCI_SUBCLASS_INPUT_MOUSE0x02, "Mouse" }, | |||
1256 | { PCI_SUBCLASS_INPUT_SCANNER0x03, "Scanner" }, | |||
1257 | { PCI_SUBCLASS_INPUT_GAMEPORT0x04, "Game Port" }, | |||
1258 | { PCI_SUBCLASS_INPUT_MISC0x80, "Miscellaneous" }, | |||
1259 | }; | |||
1260 | ||||
1261 | static const struct pci_subclass pci_subclass_dock[] = { | |||
1262 | { PCI_SUBCLASS_DOCK_GENERIC0x00, "Generic" }, | |||
1263 | { PCI_SUBCLASS_DOCK_MISC0x80, "Miscellaneous" }, | |||
1264 | }; | |||
1265 | ||||
1266 | static const struct pci_subclass pci_subclass_processor[] = { | |||
1267 | { PCI_SUBCLASS_PROCESSOR_3860x00, "386" }, | |||
1268 | { PCI_SUBCLASS_PROCESSOR_4860x01, "486" }, | |||
1269 | { PCI_SUBCLASS_PROCESSOR_PENTIUM0x02, "Pentium" }, | |||
1270 | { PCI_SUBCLASS_PROCESSOR_ALPHA0x10, "Alpha" }, | |||
1271 | { PCI_SUBCLASS_PROCESSOR_POWERPC0x20, "PowerPC" }, | |||
1272 | { PCI_SUBCLASS_PROCESSOR_MIPS0x30, "MIPS" }, | |||
1273 | { PCI_SUBCLASS_PROCESSOR_COPROC0x40, "Co-Processor" }, | |||
1274 | }; | |||
1275 | ||||
1276 | static const struct pci_subclass pci_subclass_serialbus[] = { | |||
1277 | { PCI_SUBCLASS_SERIALBUS_FIREWIRE0x00, "FireWire" }, | |||
1278 | { PCI_SUBCLASS_SERIALBUS_ACCESS0x01, "ACCESS.bus" }, | |||
1279 | { PCI_SUBCLASS_SERIALBUS_SSA0x02, "SSA" }, | |||
1280 | { PCI_SUBCLASS_SERIALBUS_USB0x03, "USB" }, | |||
1281 | { PCI_SUBCLASS_SERIALBUS_FIBER0x04, "Fiber Channel" }, | |||
1282 | { PCI_SUBCLASS_SERIALBUS_SMBUS0x05, "SMBus" }, | |||
1283 | { PCI_SUBCLASS_SERIALBUS_INFINIBAND0x06, "InfiniBand" }, | |||
1284 | { PCI_SUBCLASS_SERIALBUS_IPMI0x07, "IPMI" }, | |||
1285 | { PCI_SUBCLASS_SERIALBUS_SERCOS0x08, "SERCOS" }, | |||
1286 | { PCI_SUBCLASS_SERIALBUS_CANBUS0x09, "CANbus" }, | |||
1287 | }; | |||
1288 | ||||
1289 | static const struct pci_subclass pci_subclass_wireless[] = { | |||
1290 | { PCI_SUBCLASS_WIRELESS_IRDA0x00, "IrDA" }, | |||
1291 | { PCI_SUBCLASS_WIRELESS_CONSUMERIR0x01, "Consumer IR" }, | |||
1292 | { PCI_SUBCLASS_WIRELESS_RF0x10, "RF" }, | |||
1293 | { PCI_SUBCLASS_WIRELESS_BLUETOOTH0x11, "Bluetooth" }, | |||
1294 | { PCI_SUBCLASS_WIRELESS_BROADBAND0x12, "Broadband" }, | |||
1295 | { PCI_SUBCLASS_WIRELESS_802_11A0x20, "802.11a" }, | |||
1296 | { PCI_SUBCLASS_WIRELESS_802_11B0x21, "802.11b" }, | |||
1297 | { PCI_SUBCLASS_WIRELESS_MISC0x80, "Miscellaneous" }, | |||
1298 | }; | |||
1299 | ||||
1300 | static const struct pci_subclass pci_subclass_i2o[] = { | |||
1301 | { PCI_SUBCLASS_I2O_STANDARD0x00, "Standard" }, | |||
1302 | }; | |||
1303 | ||||
1304 | static const struct pci_subclass pci_subclass_satcom[] = { | |||
1305 | { PCI_SUBCLASS_SATCOM_TV0x01, "TV" }, | |||
1306 | { PCI_SUBCLASS_SATCOM_AUDIO0x02, "Audio" }, | |||
1307 | { PCI_SUBCLASS_SATCOM_VOICE0x03, "Voice" }, | |||
1308 | { PCI_SUBCLASS_SATCOM_DATA0x04, "Data" }, | |||
1309 | }; | |||
1310 | ||||
1311 | static const struct pci_subclass pci_subclass_crypto[] = { | |||
1312 | { PCI_SUBCLASS_CRYPTO_NETCOMP0x00, "Network/Computing" }, | |||
1313 | { PCI_SUBCLASS_CRYPTO_ENTERTAINMENT0x10, "Entertainment" }, | |||
1314 | { PCI_SUBCLASS_CRYPTO_MISC0x80, "Miscellaneous" }, | |||
1315 | }; | |||
1316 | ||||
1317 | static const struct pci_subclass pci_subclass_dasp[] = { | |||
1318 | { PCI_SUBCLASS_DASP_DPIO0x00, "DPIO" }, | |||
1319 | { PCI_SUBCLASS_DASP_TIMEFREQ0x01, "Time and Frequency" }, | |||
1320 | { PCI_SUBCLASS_DASP_SYNC0x10, "Synchronization" }, | |||
1321 | { PCI_SUBCLASS_DASP_MGMT0x20, "Management" }, | |||
1322 | { PCI_SUBCLASS_DASP_MISC0x80, "Miscellaneous" }, | |||
1323 | }; | |||
1324 | ||||
1325 | static const struct pci_subclass pci_subclass_accelerator[] = {}; | |||
1326 | static const struct pci_subclass pci_subclass_instrumentation[] = {}; | |||
1327 | ||||
1328 | #define CLASS(_c, _n, _s){ .class = _c, .name = _n, .subclass = _s, .nsubclass = (sizeof ((_s)) / sizeof((_s)[0])), } { \ | |||
1329 | .class = _c, \ | |||
1330 | .name = _n, \ | |||
1331 | .subclass = _s, \ | |||
1332 | .nsubclass = nitems(_s)(sizeof((_s)) / sizeof((_s)[0])), \ | |||
1333 | } | |||
1334 | ||||
1335 | static const struct pci_class pci_classes[] = { | |||
1336 | CLASS(PCI_CLASS_PREHISTORIC, "Prehistoric",{ .class = 0x00, .name = "Prehistoric", .subclass = pci_subclass_prehistoric , .nsubclass = (sizeof((pci_subclass_prehistoric)) / sizeof(( pci_subclass_prehistoric)[0])), } | |||
1337 | pci_subclass_prehistoric){ .class = 0x00, .name = "Prehistoric", .subclass = pci_subclass_prehistoric , .nsubclass = (sizeof((pci_subclass_prehistoric)) / sizeof(( pci_subclass_prehistoric)[0])), }, | |||
1338 | 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])), } | |||
1339 | 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])), }, | |||
1340 | CLASS(PCI_CLASS_NETWORK, "Network",{ .class = 0x02, .name = "Network", .subclass = pci_subclass_network , .nsubclass = (sizeof((pci_subclass_network)) / sizeof((pci_subclass_network )[0])), } | |||
1341 | pci_subclass_network){ .class = 0x02, .name = "Network", .subclass = pci_subclass_network , .nsubclass = (sizeof((pci_subclass_network)) / sizeof((pci_subclass_network )[0])), }, | |||
1342 | CLASS(PCI_CLASS_DISPLAY, "Display",{ .class = 0x03, .name = "Display", .subclass = pci_subclass_display , .nsubclass = (sizeof((pci_subclass_display)) / sizeof((pci_subclass_display )[0])), } | |||
1343 | pci_subclass_display){ .class = 0x03, .name = "Display", .subclass = pci_subclass_display , .nsubclass = (sizeof((pci_subclass_display)) / sizeof((pci_subclass_display )[0])), }, | |||
1344 | CLASS(PCI_CLASS_MULTIMEDIA, "Multimedia",{ .class = 0x04, .name = "Multimedia", .subclass = pci_subclass_multimedia , .nsubclass = (sizeof((pci_subclass_multimedia)) / sizeof((pci_subclass_multimedia )[0])), } | |||
1345 | pci_subclass_multimedia){ .class = 0x04, .name = "Multimedia", .subclass = pci_subclass_multimedia , .nsubclass = (sizeof((pci_subclass_multimedia)) / sizeof((pci_subclass_multimedia )[0])), }, | |||
1346 | CLASS(PCI_CLASS_MEMORY, "Memory",{ .class = 0x05, .name = "Memory", .subclass = pci_subclass_memory , .nsubclass = (sizeof((pci_subclass_memory)) / sizeof((pci_subclass_memory )[0])), } | |||
1347 | pci_subclass_memory){ .class = 0x05, .name = "Memory", .subclass = pci_subclass_memory , .nsubclass = (sizeof((pci_subclass_memory)) / sizeof((pci_subclass_memory )[0])), }, | |||
1348 | CLASS(PCI_CLASS_BRIDGE, "Bridge",{ .class = 0x06, .name = "Bridge", .subclass = pci_subclass_bridge , .nsubclass = (sizeof((pci_subclass_bridge)) / sizeof((pci_subclass_bridge )[0])), } | |||
1349 | pci_subclass_bridge){ .class = 0x06, .name = "Bridge", .subclass = pci_subclass_bridge , .nsubclass = (sizeof((pci_subclass_bridge)) / sizeof((pci_subclass_bridge )[0])), }, | |||
1350 | CLASS(PCI_CLASS_COMMUNICATIONS, "Communications",{ .class = 0x07, .name = "Communications", .subclass = pci_subclass_communications , .nsubclass = (sizeof((pci_subclass_communications)) / sizeof ((pci_subclass_communications)[0])), } | |||
1351 | pci_subclass_communications){ .class = 0x07, .name = "Communications", .subclass = pci_subclass_communications , .nsubclass = (sizeof((pci_subclass_communications)) / sizeof ((pci_subclass_communications)[0])), }, | |||
1352 | CLASS(PCI_CLASS_SYSTEM, "System",{ .class = 0x08, .name = "System", .subclass = pci_subclass_system , .nsubclass = (sizeof((pci_subclass_system)) / sizeof((pci_subclass_system )[0])), } | |||
1353 | pci_subclass_system){ .class = 0x08, .name = "System", .subclass = pci_subclass_system , .nsubclass = (sizeof((pci_subclass_system)) / sizeof((pci_subclass_system )[0])), }, | |||
1354 | CLASS(PCI_CLASS_INPUT, "Input",{ .class = 0x09, .name = "Input", .subclass = pci_subclass_input , .nsubclass = (sizeof((pci_subclass_input)) / sizeof((pci_subclass_input )[0])), } | |||
1355 | pci_subclass_input){ .class = 0x09, .name = "Input", .subclass = pci_subclass_input , .nsubclass = (sizeof((pci_subclass_input)) / sizeof((pci_subclass_input )[0])), }, | |||
1356 | CLASS(PCI_CLASS_DOCK, "Dock",{ .class = 0x0a, .name = "Dock", .subclass = pci_subclass_dock , .nsubclass = (sizeof((pci_subclass_dock)) / sizeof((pci_subclass_dock )[0])), } | |||
1357 | pci_subclass_dock){ .class = 0x0a, .name = "Dock", .subclass = pci_subclass_dock , .nsubclass = (sizeof((pci_subclass_dock)) / sizeof((pci_subclass_dock )[0])), }, | |||
1358 | CLASS(PCI_CLASS_PROCESSOR, "Processor",{ .class = 0x0b, .name = "Processor", .subclass = pci_subclass_processor , .nsubclass = (sizeof((pci_subclass_processor)) / sizeof((pci_subclass_processor )[0])), } | |||
1359 | pci_subclass_processor){ .class = 0x0b, .name = "Processor", .subclass = pci_subclass_processor , .nsubclass = (sizeof((pci_subclass_processor)) / sizeof((pci_subclass_processor )[0])), }, | |||
1360 | 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])), } | |||
1361 | pci_subclass_serialbus){ .class = 0x0c, .name = "Serial Bus", .subclass = pci_subclass_serialbus , .nsubclass = (sizeof((pci_subclass_serialbus)) / sizeof((pci_subclass_serialbus )[0])), }, | |||
1362 | CLASS(PCI_CLASS_WIRELESS, "Wireless",{ .class = 0x0d, .name = "Wireless", .subclass = pci_subclass_wireless , .nsubclass = (sizeof((pci_subclass_wireless)) / sizeof((pci_subclass_wireless )[0])), } | |||
1363 | pci_subclass_wireless){ .class = 0x0d, .name = "Wireless", .subclass = pci_subclass_wireless , .nsubclass = (sizeof((pci_subclass_wireless)) / sizeof((pci_subclass_wireless )[0])), }, | |||
1364 | CLASS(PCI_CLASS_I2O, "I2O",{ .class = 0x0e, .name = "I2O", .subclass = pci_subclass_i2o, .nsubclass = (sizeof((pci_subclass_i2o)) / sizeof((pci_subclass_i2o )[0])), } | |||
1365 | pci_subclass_i2o){ .class = 0x0e, .name = "I2O", .subclass = pci_subclass_i2o, .nsubclass = (sizeof((pci_subclass_i2o)) / sizeof((pci_subclass_i2o )[0])), }, | |||
1366 | 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])), } | |||
1367 | pci_subclass_satcom){ .class = 0x0f, .name = "Satellite Comm", .subclass = pci_subclass_satcom , .nsubclass = (sizeof((pci_subclass_satcom)) / sizeof((pci_subclass_satcom )[0])), }, | |||
1368 | CLASS(PCI_CLASS_CRYPTO, "Crypto",{ .class = 0x10, .name = "Crypto", .subclass = pci_subclass_crypto , .nsubclass = (sizeof((pci_subclass_crypto)) / sizeof((pci_subclass_crypto )[0])), } | |||
1369 | pci_subclass_crypto){ .class = 0x10, .name = "Crypto", .subclass = pci_subclass_crypto , .nsubclass = (sizeof((pci_subclass_crypto)) / sizeof((pci_subclass_crypto )[0])), }, | |||
1370 | CLASS(PCI_CLASS_DASP, "DASP",{ .class = 0x11, .name = "DASP", .subclass = pci_subclass_dasp , .nsubclass = (sizeof((pci_subclass_dasp)) / sizeof((pci_subclass_dasp )[0])), } | |||
1371 | pci_subclass_dasp){ .class = 0x11, .name = "DASP", .subclass = pci_subclass_dasp , .nsubclass = (sizeof((pci_subclass_dasp)) / sizeof((pci_subclass_dasp )[0])), }, | |||
1372 | CLASS(PCI_CLASS_ACCELERATOR, "Accelerator",{ .class = 0x12, .name = "Accelerator", .subclass = pci_subclass_accelerator , .nsubclass = (sizeof((pci_subclass_accelerator)) / sizeof(( pci_subclass_accelerator)[0])), } | |||
1373 | pci_subclass_accelerator){ .class = 0x12, .name = "Accelerator", .subclass = pci_subclass_accelerator , .nsubclass = (sizeof((pci_subclass_accelerator)) / sizeof(( pci_subclass_accelerator)[0])), }, | |||
1374 | CLASS(PCI_CLASS_INSTRUMENTATION, "Instrumentation",{ .class = 0x13, .name = "Instrumentation", .subclass = pci_subclass_instrumentation , .nsubclass = (sizeof((pci_subclass_instrumentation)) / sizeof ((pci_subclass_instrumentation)[0])), } | |||
1375 | pci_subclass_instrumentation){ .class = 0x13, .name = "Instrumentation", .subclass = pci_subclass_instrumentation , .nsubclass = (sizeof((pci_subclass_instrumentation)) / sizeof ((pci_subclass_instrumentation)[0])), }, | |||
1376 | }; | |||
1377 | ||||
1378 | static const struct pci_class * | |||
1379 | pci_class(pci_class_t class) | |||
1380 | { | |||
1381 | const struct pci_class *pc; | |||
1382 | size_t i; | |||
1383 | ||||
1384 | for (i = 0; i < nitems(pci_classes)(sizeof((pci_classes)) / sizeof((pci_classes)[0])); i++) { | |||
1385 | pc = &pci_classes[i]; | |||
1386 | if (pc->class == class) | |||
1387 | return (pc); | |||
1388 | } | |||
1389 | ||||
1390 | return (NULL((void *)0)); | |||
1391 | } | |||
1392 | ||||
1393 | static const struct pci_subclass * | |||
1394 | pci_subclass(const struct pci_class *pc, pci_subclass_t subclass) | |||
1395 | { | |||
1396 | const struct pci_subclass *ps; | |||
1397 | size_t i; | |||
1398 | ||||
1399 | for (i = 0; i < pc->nsubclass; i++) { | |||
1400 | ps = &pc->subclass[i]; | |||
1401 | if (ps->subclass == subclass) | |||
1402 | return (ps); | |||
1403 | } | |||
1404 | ||||
1405 | return (NULL((void *)0)); | |||
1406 | } | |||
1407 | ||||
1408 | static const char * | |||
1409 | pci_class_name(pci_class_t class) | |||
1410 | { | |||
1411 | const struct pci_class *pc; | |||
1412 | ||||
1413 | pc = pci_class(class); | |||
1414 | if (pc == NULL((void *)0)) | |||
1415 | return ("(unknown)"); | |||
1416 | ||||
1417 | return (pc->name); | |||
1418 | } | |||
1419 | ||||
1420 | static const char * | |||
1421 | pci_subclass_name(pci_class_t class, pci_subclass_t subclass) | |||
1422 | { | |||
1423 | const struct pci_class *pc; | |||
1424 | const struct pci_subclass *ps; | |||
1425 | ||||
1426 | pc = pci_class(class); | |||
1427 | if (pc == NULL((void *)0)) | |||
1428 | return ("(unknown)"); | |||
1429 | ||||
1430 | ps = pci_subclass(pc, subclass); | |||
1431 | if (ps == NULL((void *)0) || ps->name == NULL((void *)0)) | |||
1432 | return ("(unknown)"); | |||
1433 | ||||
1434 | return (ps->name); | |||
1435 | } |