1 /* 2 * Copyright 1996 Massachusetts Institute of Technology 3 * 4 * Permission to use, copy, modify, and distribute this software and 5 * its documentation for any purpose and without fee is hereby 6 * granted, provided that both the above copyright notice and this 7 * permission notice appear in all copies, that both the above 8 * copyright notice and this permission notice appear in all 9 * supporting documentation, and that the name of M.I.T. not be used 10 * in advertising or publicity pertaining to distribution of the 11 * software without specific, written prior permission. M.I.T. makes 12 * no representations about the suitability of this software for any 13 * purpose. It is provided "as is" without express or implied 14 * warranty. 15 * 16 * THIS SOFTWARE IS PROVIDED BY M.I.T. ``AS IS''. M.I.T. DISCLAIMS 17 * ALL EXPRESS OR IMPLIED WARRANTIES WITH REGARD TO THIS SOFTWARE, 18 * INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF 19 * MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE. IN NO EVENT 20 * SHALL M.I.T. BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 21 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 22 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF 23 * USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND 24 * ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, 25 * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT 26 * OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 27 * SUCH DAMAGE. 28 */ 29 30 #ifndef lint 31 static const char rcsid[] = 32 "$FreeBSD$"; 33 #endif /* not lint */ 34 35 #include <sys/types.h> 36 #include <sys/fcntl.h> 37 #include <sys/mman.h> 38 #include <sys/pciio.h> 39 #include <sys/queue.h> 40 41 #include <vm/vm.h> 42 43 #include <dev/pci/pcireg.h> 44 45 #include <assert.h> 46 #include <ctype.h> 47 #include <err.h> 48 #include <inttypes.h> 49 #include <stdbool.h> 50 #include <stdlib.h> 51 #include <stdio.h> 52 #include <string.h> 53 #include <unistd.h> 54 55 #include "pathnames.h" 56 #include "pciconf.h" 57 58 struct pci_device_info 59 { 60 TAILQ_ENTRY(pci_device_info) link; 61 int id; 62 char *desc; 63 }; 64 65 struct pci_vendor_info 66 { 67 TAILQ_ENTRY(pci_vendor_info) link; 68 TAILQ_HEAD(,pci_device_info) devs; 69 int id; 70 char *desc; 71 }; 72 73 static TAILQ_HEAD(,pci_vendor_info) pci_vendors; 74 75 static struct pcisel getsel(const char *str); 76 static void list_bridge(int fd, struct pci_conf *p); 77 static void list_bars(int fd, struct pci_conf *p); 78 static void list_devs(const char *name, int verbose, int bars, int bridge, 79 int caps, int errors, int vpd); 80 static void list_verbose(struct pci_conf *p); 81 static void list_vpd(int fd, struct pci_conf *p); 82 static const char *guess_class(struct pci_conf *p); 83 static const char *guess_subclass(struct pci_conf *p); 84 static int load_vendors(void); 85 static void readit(const char *, const char *, int); 86 static void writeit(const char *, const char *, const char *, int); 87 static void chkattached(const char *); 88 static void dump_bar(const char *name, const char *reg, const char *bar_start, 89 const char *bar_count, int width, int verbose); 90 91 static int exitstatus = 0; 92 93 static void 94 usage(void) 95 { 96 97 fprintf(stderr, "%s", 98 "usage: pciconf -l [-BbcevV] [device]\n" 99 " pciconf -a device\n" 100 " pciconf -r [-b | -h] device addr[:addr2]\n" 101 " pciconf -w [-b | -h] device addr value\n" 102 " pciconf -D [-b | -h | -x] device bar [start [count]]" 103 "\n"); 104 exit(1); 105 } 106 107 int 108 main(int argc, char **argv) 109 { 110 int c, width; 111 int listmode, readmode, writemode, attachedmode, dumpbarmode; 112 int bars, bridge, caps, errors, verbose, vpd; 113 114 listmode = readmode = writemode = attachedmode = dumpbarmode = 0; 115 bars = bridge = caps = errors = verbose = vpd= 0; 116 width = 4; 117 118 while ((c = getopt(argc, argv, "aBbcDehlrwVv")) != -1) { 119 switch(c) { 120 case 'a': 121 attachedmode = 1; 122 break; 123 124 case 'B': 125 bridge = 1; 126 break; 127 128 case 'b': 129 bars = 1; 130 width = 1; 131 break; 132 133 case 'c': 134 caps = 1; 135 break; 136 137 case 'D': 138 dumpbarmode = 1; 139 break; 140 141 case 'e': 142 errors = 1; 143 break; 144 145 case 'h': 146 width = 2; 147 break; 148 149 case 'l': 150 listmode = 1; 151 break; 152 153 case 'r': 154 readmode = 1; 155 break; 156 157 case 'w': 158 writemode = 1; 159 break; 160 161 case 'v': 162 verbose = 1; 163 break; 164 165 case 'V': 166 vpd = 1; 167 break; 168 169 case 'x': 170 width = 8; 171 break; 172 173 default: 174 usage(); 175 } 176 } 177 178 if ((listmode && optind >= argc + 1) 179 || (writemode && optind + 3 != argc) 180 || (readmode && optind + 2 != argc) 181 || (attachedmode && optind + 1 != argc) 182 || (dumpbarmode && (optind + 2 > argc || optind + 4 < argc)) 183 || (width == 8 && !dumpbarmode)) 184 usage(); 185 186 if (listmode) { 187 list_devs(optind + 1 == argc ? argv[optind] : NULL, verbose, 188 bars, bridge, caps, errors, vpd); 189 } else if (attachedmode) { 190 chkattached(argv[optind]); 191 } else if (readmode) { 192 readit(argv[optind], argv[optind + 1], width); 193 } else if (writemode) { 194 writeit(argv[optind], argv[optind + 1], argv[optind + 2], 195 width); 196 } else if (dumpbarmode) { 197 dump_bar(argv[optind], argv[optind + 1], 198 optind + 2 < argc ? argv[optind + 2] : NULL, 199 optind + 3 < argc ? argv[optind + 3] : NULL, 200 width, verbose); 201 } else { 202 usage(); 203 } 204 205 return (exitstatus); 206 } 207 208 static void 209 list_devs(const char *name, int verbose, int bars, int bridge, int caps, 210 int errors, int vpd) 211 { 212 int fd; 213 struct pci_conf_io pc; 214 struct pci_conf conf[255], *p; 215 struct pci_match_conf patterns[1]; 216 int none_count = 0; 217 218 if (verbose) 219 load_vendors(); 220 221 fd = open(_PATH_DEVPCI, (bridge || caps || errors) ? O_RDWR : O_RDONLY, 222 0); 223 if (fd < 0) 224 err(1, "%s", _PATH_DEVPCI); 225 226 bzero(&pc, sizeof(struct pci_conf_io)); 227 pc.match_buf_len = sizeof(conf); 228 pc.matches = conf; 229 if (name != NULL) { 230 bzero(&patterns, sizeof(patterns)); 231 patterns[0].pc_sel = getsel(name); 232 patterns[0].flags = PCI_GETCONF_MATCH_DOMAIN | 233 PCI_GETCONF_MATCH_BUS | PCI_GETCONF_MATCH_DEV | 234 PCI_GETCONF_MATCH_FUNC; 235 pc.num_patterns = 1; 236 pc.pat_buf_len = sizeof(patterns); 237 pc.patterns = patterns; 238 } 239 240 do { 241 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 242 err(1, "ioctl(PCIOCGETCONF)"); 243 244 /* 245 * 255 entries should be more than enough for most people, 246 * but if someone has more devices, and then changes things 247 * around between ioctls, we'll do the cheesy thing and 248 * just bail. The alternative would be to go back to the 249 * beginning of the list, and print things twice, which may 250 * not be desirable. 251 */ 252 if (pc.status == PCI_GETCONF_LIST_CHANGED) { 253 warnx("PCI device list changed, please try again"); 254 exitstatus = 1; 255 close(fd); 256 return; 257 } else if (pc.status == PCI_GETCONF_ERROR) { 258 warnx("error returned from PCIOCGETCONF ioctl"); 259 exitstatus = 1; 260 close(fd); 261 return; 262 } 263 for (p = conf; p < &conf[pc.num_matches]; p++) { 264 printf("%s%d@pci%d:%d:%d:%d:" 265 "\tclass=0x%06x rev=0x%02x hdr=0x%02x " 266 "vendor=0x%04x device=0x%04x " 267 "subvendor=0x%04x subdevice=0x%04x\n", 268 *p->pd_name ? p->pd_name : 269 "none", 270 *p->pd_name ? (int)p->pd_unit : 271 none_count++, p->pc_sel.pc_domain, 272 p->pc_sel.pc_bus, p->pc_sel.pc_dev, 273 p->pc_sel.pc_func, (p->pc_class << 16) | 274 (p->pc_subclass << 8) | p->pc_progif, 275 p->pc_revid, p->pc_hdr, 276 p->pc_vendor, p->pc_device, 277 p->pc_subvendor, p->pc_subdevice); 278 if (verbose) 279 list_verbose(p); 280 if (bars) 281 list_bars(fd, p); 282 if (bridge) 283 list_bridge(fd, p); 284 if (caps) 285 list_caps(fd, p); 286 if (errors) 287 list_errors(fd, p); 288 if (vpd) 289 list_vpd(fd, p); 290 } 291 } while (pc.status == PCI_GETCONF_MORE_DEVS); 292 293 close(fd); 294 } 295 296 static void 297 print_bus_range(int fd, struct pci_conf *p, int secreg, int subreg) 298 { 299 uint8_t secbus, subbus; 300 301 secbus = read_config(fd, &p->pc_sel, secreg, 1); 302 subbus = read_config(fd, &p->pc_sel, subreg, 1); 303 printf(" bus range = %u-%u\n", secbus, subbus); 304 } 305 306 static void 307 print_window(int reg, const char *type, int range, uint64_t base, 308 uint64_t limit) 309 { 310 311 printf(" window[%02x] = type %s, range %2d, addr %#jx-%#jx, %s\n", 312 reg, type, range, (uintmax_t)base, (uintmax_t)limit, 313 base < limit ? "enabled" : "disabled"); 314 } 315 316 static void 317 print_special_decode(bool isa, bool vga, bool subtractive) 318 { 319 bool comma; 320 321 if (isa || vga || subtractive) { 322 comma = false; 323 printf(" decode = "); 324 if (isa) { 325 printf("ISA"); 326 comma = true; 327 } 328 if (vga) { 329 printf("%sVGA", comma ? ", " : ""); 330 comma = true; 331 } 332 if (subtractive) 333 printf("%ssubtractive", comma ? ", " : ""); 334 printf("\n"); 335 } 336 } 337 338 static void 339 print_bridge_windows(int fd, struct pci_conf *p) 340 { 341 uint64_t base, limit; 342 uint32_t val; 343 uint16_t bctl; 344 bool subtractive; 345 int range; 346 347 /* 348 * XXX: This assumes that a window with a base and limit of 0 349 * is not implemented. In theory a window might be programmed 350 * at the smallest size with a base of 0, but those do not seem 351 * common in practice. 352 */ 353 val = read_config(fd, &p->pc_sel, PCIR_IOBASEL_1, 1); 354 if (val != 0 || read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1) != 0) { 355 if ((val & PCIM_BRIO_MASK) == PCIM_BRIO_32) { 356 base = PCI_PPBIOBASE( 357 read_config(fd, &p->pc_sel, PCIR_IOBASEH_1, 2), 358 val); 359 limit = PCI_PPBIOLIMIT( 360 read_config(fd, &p->pc_sel, PCIR_IOLIMITH_1, 2), 361 read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 362 range = 32; 363 } else { 364 base = PCI_PPBIOBASE(0, val); 365 limit = PCI_PPBIOLIMIT(0, 366 read_config(fd, &p->pc_sel, PCIR_IOLIMITL_1, 1)); 367 range = 16; 368 } 369 print_window(PCIR_IOBASEL_1, "I/O Port", range, base, limit); 370 } 371 372 base = PCI_PPBMEMBASE(0, 373 read_config(fd, &p->pc_sel, PCIR_MEMBASE_1, 2)); 374 limit = PCI_PPBMEMLIMIT(0, 375 read_config(fd, &p->pc_sel, PCIR_MEMLIMIT_1, 2)); 376 print_window(PCIR_MEMBASE_1, "Memory", 32, base, limit); 377 378 val = read_config(fd, &p->pc_sel, PCIR_PMBASEL_1, 2); 379 if (val != 0 || read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2) != 0) { 380 if ((val & PCIM_BRPM_MASK) == PCIM_BRPM_64) { 381 base = PCI_PPBMEMBASE( 382 read_config(fd, &p->pc_sel, PCIR_PMBASEH_1, 4), 383 val); 384 limit = PCI_PPBMEMLIMIT( 385 read_config(fd, &p->pc_sel, PCIR_PMLIMITH_1, 4), 386 read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 387 range = 64; 388 } else { 389 base = PCI_PPBMEMBASE(0, val); 390 limit = PCI_PPBMEMLIMIT(0, 391 read_config(fd, &p->pc_sel, PCIR_PMLIMITL_1, 2)); 392 range = 32; 393 } 394 print_window(PCIR_PMBASEL_1, "Prefetchable Memory", range, base, 395 limit); 396 } 397 398 /* 399 * XXX: This list of bridges that are subtractive but do not set 400 * progif to indicate it is copied from pci_pci.c. 401 */ 402 subtractive = p->pc_progif == PCIP_BRIDGE_PCI_SUBTRACTIVE; 403 switch (p->pc_device << 16 | p->pc_vendor) { 404 case 0xa002177d: /* Cavium ThunderX */ 405 case 0x124b8086: /* Intel 82380FB Mobile */ 406 case 0x060513d7: /* Toshiba ???? */ 407 subtractive = true; 408 } 409 if (p->pc_vendor == 0x8086 && (p->pc_device & 0xff00) == 0x2400) 410 subtractive = true; 411 412 bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_1, 2); 413 print_special_decode(bctl & PCIB_BCR_ISA_ENABLE, 414 bctl & PCIB_BCR_VGA_ENABLE, subtractive); 415 } 416 417 static void 418 print_cardbus_mem_window(int fd, struct pci_conf *p, int basereg, int limitreg, 419 bool prefetch) 420 { 421 422 print_window(basereg, prefetch ? "Prefetchable Memory" : "Memory", 32, 423 PCI_CBBMEMBASE(read_config(fd, &p->pc_sel, basereg, 4)), 424 PCI_CBBMEMLIMIT(read_config(fd, &p->pc_sel, limitreg, 4))); 425 } 426 427 static void 428 print_cardbus_io_window(int fd, struct pci_conf *p, int basereg, int limitreg) 429 { 430 uint32_t base, limit; 431 uint32_t val; 432 int range; 433 434 val = read_config(fd, &p->pc_sel, basereg, 2); 435 if ((val & PCIM_CBBIO_MASK) == PCIM_CBBIO_32) { 436 base = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, basereg, 4)); 437 limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 4)); 438 range = 32; 439 } else { 440 base = PCI_CBBIOBASE(val); 441 limit = PCI_CBBIOBASE(read_config(fd, &p->pc_sel, limitreg, 2)); 442 range = 16; 443 } 444 print_window(basereg, "I/O Port", range, base, limit); 445 } 446 447 static void 448 print_cardbus_windows(int fd, struct pci_conf *p) 449 { 450 uint16_t bctl; 451 452 bctl = read_config(fd, &p->pc_sel, PCIR_BRIDGECTL_2, 2); 453 print_cardbus_mem_window(fd, p, PCIR_MEMBASE0_2, PCIR_MEMLIMIT0_2, 454 bctl & CBB_BCR_PREFETCH_0_ENABLE); 455 print_cardbus_mem_window(fd, p, PCIR_MEMBASE1_2, PCIR_MEMLIMIT1_2, 456 bctl & CBB_BCR_PREFETCH_1_ENABLE); 457 print_cardbus_io_window(fd, p, PCIR_IOBASE0_2, PCIR_IOLIMIT0_2); 458 print_cardbus_io_window(fd, p, PCIR_IOBASE1_2, PCIR_IOLIMIT1_2); 459 print_special_decode(bctl & CBB_BCR_ISA_ENABLE, 460 bctl & CBB_BCR_VGA_ENABLE, false); 461 } 462 463 static void 464 list_bridge(int fd, struct pci_conf *p) 465 { 466 467 switch (p->pc_hdr & PCIM_HDRTYPE) { 468 case PCIM_HDRTYPE_BRIDGE: 469 print_bus_range(fd, p, PCIR_SECBUS_1, PCIR_SUBBUS_1); 470 print_bridge_windows(fd, p); 471 break; 472 case PCIM_HDRTYPE_CARDBUS: 473 print_bus_range(fd, p, PCIR_SECBUS_2, PCIR_SUBBUS_2); 474 print_cardbus_windows(fd, p); 475 break; 476 } 477 } 478 479 static void 480 list_bars(int fd, struct pci_conf *p) 481 { 482 int i, max; 483 484 switch (p->pc_hdr & PCIM_HDRTYPE) { 485 case PCIM_HDRTYPE_NORMAL: 486 max = PCIR_MAX_BAR_0; 487 break; 488 case PCIM_HDRTYPE_BRIDGE: 489 max = PCIR_MAX_BAR_1; 490 break; 491 case PCIM_HDRTYPE_CARDBUS: 492 max = PCIR_MAX_BAR_2; 493 break; 494 default: 495 return; 496 } 497 498 for (i = 0; i <= max; i++) 499 print_bar(fd, p, "bar ", PCIR_BAR(i)); 500 } 501 502 void 503 print_bar(int fd, struct pci_conf *p, const char *label, uint16_t bar_offset) 504 { 505 uint64_t base; 506 const char *type; 507 struct pci_bar_io bar; 508 int range; 509 510 bar.pbi_sel = p->pc_sel; 511 bar.pbi_reg = bar_offset; 512 if (ioctl(fd, PCIOCGETBAR, &bar) < 0) 513 return; 514 if (PCI_BAR_IO(bar.pbi_base)) { 515 type = "I/O Port"; 516 range = 32; 517 base = bar.pbi_base & PCIM_BAR_IO_BASE; 518 } else { 519 if (bar.pbi_base & PCIM_BAR_MEM_PREFETCH) 520 type = "Prefetchable Memory"; 521 else 522 type = "Memory"; 523 switch (bar.pbi_base & PCIM_BAR_MEM_TYPE) { 524 case PCIM_BAR_MEM_32: 525 range = 32; 526 break; 527 case PCIM_BAR_MEM_1MB: 528 range = 20; 529 break; 530 case PCIM_BAR_MEM_64: 531 range = 64; 532 break; 533 default: 534 range = -1; 535 } 536 base = bar.pbi_base & ~((uint64_t)0xf); 537 } 538 printf(" %s[%02x] = type %s, range %2d, base %#jx, ", 539 label, bar_offset, type, range, (uintmax_t)base); 540 printf("size %ju, %s\n", (uintmax_t)bar.pbi_length, 541 bar.pbi_enabled ? "enabled" : "disabled"); 542 } 543 544 static void 545 list_verbose(struct pci_conf *p) 546 { 547 struct pci_vendor_info *vi; 548 struct pci_device_info *di; 549 const char *dp; 550 551 TAILQ_FOREACH(vi, &pci_vendors, link) { 552 if (vi->id == p->pc_vendor) { 553 printf(" vendor = '%s'\n", vi->desc); 554 break; 555 } 556 } 557 if (vi == NULL) { 558 di = NULL; 559 } else { 560 TAILQ_FOREACH(di, &vi->devs, link) { 561 if (di->id == p->pc_device) { 562 printf(" device = '%s'\n", di->desc); 563 break; 564 } 565 } 566 } 567 if ((dp = guess_class(p)) != NULL) 568 printf(" class = %s\n", dp); 569 if ((dp = guess_subclass(p)) != NULL) 570 printf(" subclass = %s\n", dp); 571 } 572 573 static void 574 list_vpd(int fd, struct pci_conf *p) 575 { 576 struct pci_list_vpd_io list; 577 struct pci_vpd_element *vpd, *end; 578 579 list.plvi_sel = p->pc_sel; 580 list.plvi_len = 0; 581 list.plvi_data = NULL; 582 if (ioctl(fd, PCIOCLISTVPD, &list) < 0 || list.plvi_len == 0) 583 return; 584 585 list.plvi_data = malloc(list.plvi_len); 586 if (ioctl(fd, PCIOCLISTVPD, &list) < 0) { 587 free(list.plvi_data); 588 return; 589 } 590 591 vpd = list.plvi_data; 592 end = (struct pci_vpd_element *)((char *)vpd + list.plvi_len); 593 for (; vpd < end; vpd = PVE_NEXT(vpd)) { 594 if (vpd->pve_flags == PVE_FLAG_IDENT) { 595 printf(" VPD ident = '%.*s'\n", 596 (int)vpd->pve_datalen, vpd->pve_data); 597 continue; 598 } 599 600 /* Ignore the checksum keyword. */ 601 if (!(vpd->pve_flags & PVE_FLAG_RW) && 602 memcmp(vpd->pve_keyword, "RV", 2) == 0) 603 continue; 604 605 /* Ignore remaining read-write space. */ 606 if (vpd->pve_flags & PVE_FLAG_RW && 607 memcmp(vpd->pve_keyword, "RW", 2) == 0) 608 continue; 609 610 /* Handle extended capability keyword. */ 611 if (!(vpd->pve_flags & PVE_FLAG_RW) && 612 memcmp(vpd->pve_keyword, "CP", 2) == 0) { 613 printf(" VPD ro CP = ID %02x in map 0x%x[0x%x]\n", 614 (unsigned int)vpd->pve_data[0], 615 PCIR_BAR((unsigned int)vpd->pve_data[1]), 616 (unsigned int)vpd->pve_data[3] << 8 | 617 (unsigned int)vpd->pve_data[2]); 618 continue; 619 } 620 621 /* Remaining keywords should all have ASCII values. */ 622 printf(" VPD %s %c%c = '%.*s'\n", 623 vpd->pve_flags & PVE_FLAG_RW ? "rw" : "ro", 624 vpd->pve_keyword[0], vpd->pve_keyword[1], 625 (int)vpd->pve_datalen, vpd->pve_data); 626 } 627 free(list.plvi_data); 628 } 629 630 /* 631 * This is a direct cut-and-paste from the table in sys/dev/pci/pci.c. 632 */ 633 static struct 634 { 635 int class; 636 int subclass; 637 const char *desc; 638 } pci_nomatch_tab[] = { 639 {PCIC_OLD, -1, "old"}, 640 {PCIC_OLD, PCIS_OLD_NONVGA, "non-VGA display device"}, 641 {PCIC_OLD, PCIS_OLD_VGA, "VGA-compatible display device"}, 642 {PCIC_STORAGE, -1, "mass storage"}, 643 {PCIC_STORAGE, PCIS_STORAGE_SCSI, "SCSI"}, 644 {PCIC_STORAGE, PCIS_STORAGE_IDE, "ATA"}, 645 {PCIC_STORAGE, PCIS_STORAGE_FLOPPY, "floppy disk"}, 646 {PCIC_STORAGE, PCIS_STORAGE_IPI, "IPI"}, 647 {PCIC_STORAGE, PCIS_STORAGE_RAID, "RAID"}, 648 {PCIC_STORAGE, PCIS_STORAGE_ATA_ADMA, "ATA (ADMA)"}, 649 {PCIC_STORAGE, PCIS_STORAGE_SATA, "SATA"}, 650 {PCIC_STORAGE, PCIS_STORAGE_SAS, "SAS"}, 651 {PCIC_STORAGE, PCIS_STORAGE_NVM, "NVM"}, 652 {PCIC_NETWORK, -1, "network"}, 653 {PCIC_NETWORK, PCIS_NETWORK_ETHERNET, "ethernet"}, 654 {PCIC_NETWORK, PCIS_NETWORK_TOKENRING, "token ring"}, 655 {PCIC_NETWORK, PCIS_NETWORK_FDDI, "fddi"}, 656 {PCIC_NETWORK, PCIS_NETWORK_ATM, "ATM"}, 657 {PCIC_NETWORK, PCIS_NETWORK_ISDN, "ISDN"}, 658 {PCIC_DISPLAY, -1, "display"}, 659 {PCIC_DISPLAY, PCIS_DISPLAY_VGA, "VGA"}, 660 {PCIC_DISPLAY, PCIS_DISPLAY_XGA, "XGA"}, 661 {PCIC_DISPLAY, PCIS_DISPLAY_3D, "3D"}, 662 {PCIC_MULTIMEDIA, -1, "multimedia"}, 663 {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_VIDEO, "video"}, 664 {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_AUDIO, "audio"}, 665 {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_TELE, "telephony"}, 666 {PCIC_MULTIMEDIA, PCIS_MULTIMEDIA_HDA, "HDA"}, 667 {PCIC_MEMORY, -1, "memory"}, 668 {PCIC_MEMORY, PCIS_MEMORY_RAM, "RAM"}, 669 {PCIC_MEMORY, PCIS_MEMORY_FLASH, "flash"}, 670 {PCIC_BRIDGE, -1, "bridge"}, 671 {PCIC_BRIDGE, PCIS_BRIDGE_HOST, "HOST-PCI"}, 672 {PCIC_BRIDGE, PCIS_BRIDGE_ISA, "PCI-ISA"}, 673 {PCIC_BRIDGE, PCIS_BRIDGE_EISA, "PCI-EISA"}, 674 {PCIC_BRIDGE, PCIS_BRIDGE_MCA, "PCI-MCA"}, 675 {PCIC_BRIDGE, PCIS_BRIDGE_PCI, "PCI-PCI"}, 676 {PCIC_BRIDGE, PCIS_BRIDGE_PCMCIA, "PCI-PCMCIA"}, 677 {PCIC_BRIDGE, PCIS_BRIDGE_NUBUS, "PCI-NuBus"}, 678 {PCIC_BRIDGE, PCIS_BRIDGE_CARDBUS, "PCI-CardBus"}, 679 {PCIC_BRIDGE, PCIS_BRIDGE_RACEWAY, "PCI-RACEway"}, 680 {PCIC_SIMPLECOMM, -1, "simple comms"}, 681 {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_UART, "UART"}, /* could detect 16550 */ 682 {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_PAR, "parallel port"}, 683 {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MULSER, "multiport serial"}, 684 {PCIC_SIMPLECOMM, PCIS_SIMPLECOMM_MODEM, "generic modem"}, 685 {PCIC_BASEPERIPH, -1, "base peripheral"}, 686 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PIC, "interrupt controller"}, 687 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_DMA, "DMA controller"}, 688 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_TIMER, "timer"}, 689 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_RTC, "realtime clock"}, 690 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_PCIHOT, "PCI hot-plug controller"}, 691 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_SDHC, "SD host controller"}, 692 {PCIC_BASEPERIPH, PCIS_BASEPERIPH_IOMMU, "IOMMU"}, 693 {PCIC_INPUTDEV, -1, "input device"}, 694 {PCIC_INPUTDEV, PCIS_INPUTDEV_KEYBOARD, "keyboard"}, 695 {PCIC_INPUTDEV, PCIS_INPUTDEV_DIGITIZER,"digitizer"}, 696 {PCIC_INPUTDEV, PCIS_INPUTDEV_MOUSE, "mouse"}, 697 {PCIC_INPUTDEV, PCIS_INPUTDEV_SCANNER, "scanner"}, 698 {PCIC_INPUTDEV, PCIS_INPUTDEV_GAMEPORT, "gameport"}, 699 {PCIC_DOCKING, -1, "docking station"}, 700 {PCIC_PROCESSOR, -1, "processor"}, 701 {PCIC_SERIALBUS, -1, "serial bus"}, 702 {PCIC_SERIALBUS, PCIS_SERIALBUS_FW, "FireWire"}, 703 {PCIC_SERIALBUS, PCIS_SERIALBUS_ACCESS, "AccessBus"}, 704 {PCIC_SERIALBUS, PCIS_SERIALBUS_SSA, "SSA"}, 705 {PCIC_SERIALBUS, PCIS_SERIALBUS_USB, "USB"}, 706 {PCIC_SERIALBUS, PCIS_SERIALBUS_FC, "Fibre Channel"}, 707 {PCIC_SERIALBUS, PCIS_SERIALBUS_SMBUS, "SMBus"}, 708 {PCIC_WIRELESS, -1, "wireless controller"}, 709 {PCIC_WIRELESS, PCIS_WIRELESS_IRDA, "iRDA"}, 710 {PCIC_WIRELESS, PCIS_WIRELESS_IR, "IR"}, 711 {PCIC_WIRELESS, PCIS_WIRELESS_RF, "RF"}, 712 {PCIC_INTELLIIO, -1, "intelligent I/O controller"}, 713 {PCIC_INTELLIIO, PCIS_INTELLIIO_I2O, "I2O"}, 714 {PCIC_SATCOM, -1, "satellite communication"}, 715 {PCIC_SATCOM, PCIS_SATCOM_TV, "sat TV"}, 716 {PCIC_SATCOM, PCIS_SATCOM_AUDIO, "sat audio"}, 717 {PCIC_SATCOM, PCIS_SATCOM_VOICE, "sat voice"}, 718 {PCIC_SATCOM, PCIS_SATCOM_DATA, "sat data"}, 719 {PCIC_CRYPTO, -1, "encrypt/decrypt"}, 720 {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "network/computer crypto"}, 721 {PCIC_CRYPTO, PCIS_CRYPTO_NETCOMP, "entertainment crypto"}, 722 {PCIC_DASP, -1, "dasp"}, 723 {PCIC_DASP, PCIS_DASP_DPIO, "DPIO module"}, 724 {PCIC_DASP, PCIS_DASP_PERFCNTRS, "performance counters"}, 725 {PCIC_DASP, PCIS_DASP_COMM_SYNC, "communication synchronizer"}, 726 {PCIC_DASP, PCIS_DASP_MGMT_CARD, "signal processing management"}, 727 {PCIC_ACCEL, -1, "processing accelerators"}, 728 {PCIC_ACCEL, PCIS_ACCEL_PROCESSING, "processing accelerators"}, 729 {PCIC_INSTRUMENT, -1, "non-essential instrumentation"}, 730 {0, 0, NULL} 731 }; 732 733 static const char * 734 guess_class(struct pci_conf *p) 735 { 736 int i; 737 738 for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 739 if (pci_nomatch_tab[i].class == p->pc_class) 740 return(pci_nomatch_tab[i].desc); 741 } 742 return(NULL); 743 } 744 745 static const char * 746 guess_subclass(struct pci_conf *p) 747 { 748 int i; 749 750 for (i = 0; pci_nomatch_tab[i].desc != NULL; i++) { 751 if ((pci_nomatch_tab[i].class == p->pc_class) && 752 (pci_nomatch_tab[i].subclass == p->pc_subclass)) 753 return(pci_nomatch_tab[i].desc); 754 } 755 return(NULL); 756 } 757 758 static int 759 load_vendors(void) 760 { 761 const char *dbf; 762 FILE *db; 763 struct pci_vendor_info *cv; 764 struct pci_device_info *cd; 765 char buf[1024], str[1024]; 766 char *ch; 767 int id, error; 768 769 /* 770 * Locate the database and initialise. 771 */ 772 TAILQ_INIT(&pci_vendors); 773 if ((dbf = getenv("PCICONF_VENDOR_DATABASE")) == NULL) 774 dbf = _PATH_LPCIVDB; 775 if ((db = fopen(dbf, "r")) == NULL) { 776 dbf = _PATH_PCIVDB; 777 if ((db = fopen(dbf, "r")) == NULL) 778 return(1); 779 } 780 cv = NULL; 781 cd = NULL; 782 error = 0; 783 784 /* 785 * Scan input lines from the database 786 */ 787 for (;;) { 788 if (fgets(buf, sizeof(buf), db) == NULL) 789 break; 790 791 if ((ch = strchr(buf, '#')) != NULL) 792 *ch = '\0'; 793 ch = strchr(buf, '\0') - 1; 794 while (ch > buf && isspace(*ch)) 795 *ch-- = '\0'; 796 if (ch <= buf) 797 continue; 798 799 /* Can't handle subvendor / subdevice entries yet */ 800 if (buf[0] == '\t' && buf[1] == '\t') 801 continue; 802 803 /* Check for vendor entry */ 804 if (buf[0] != '\t' && sscanf(buf, "%04x %[^\n]", &id, str) == 2) { 805 if ((id == 0) || (strlen(str) < 1)) 806 continue; 807 if ((cv = malloc(sizeof(struct pci_vendor_info))) == NULL) { 808 warn("allocating vendor entry"); 809 error = 1; 810 break; 811 } 812 if ((cv->desc = strdup(str)) == NULL) { 813 free(cv); 814 warn("allocating vendor description"); 815 error = 1; 816 break; 817 } 818 cv->id = id; 819 TAILQ_INIT(&cv->devs); 820 TAILQ_INSERT_TAIL(&pci_vendors, cv, link); 821 continue; 822 } 823 824 /* Check for device entry */ 825 if (buf[0] == '\t' && sscanf(buf + 1, "%04x %[^\n]", &id, str) == 2) { 826 if ((id == 0) || (strlen(str) < 1)) 827 continue; 828 if (cv == NULL) { 829 warnx("device entry with no vendor!"); 830 continue; 831 } 832 if ((cd = malloc(sizeof(struct pci_device_info))) == NULL) { 833 warn("allocating device entry"); 834 error = 1; 835 break; 836 } 837 if ((cd->desc = strdup(str)) == NULL) { 838 free(cd); 839 warn("allocating device description"); 840 error = 1; 841 break; 842 } 843 cd->id = id; 844 TAILQ_INSERT_TAIL(&cv->devs, cd, link); 845 continue; 846 } 847 848 /* It's a comment or junk, ignore it */ 849 } 850 if (ferror(db)) 851 error = 1; 852 fclose(db); 853 854 return(error); 855 } 856 857 uint32_t 858 read_config(int fd, struct pcisel *sel, long reg, int width) 859 { 860 struct pci_io pi; 861 862 pi.pi_sel = *sel; 863 pi.pi_reg = reg; 864 pi.pi_width = width; 865 866 if (ioctl(fd, PCIOCREAD, &pi) < 0) 867 err(1, "ioctl(PCIOCREAD)"); 868 869 return (pi.pi_data); 870 } 871 872 static struct pcisel 873 getdevice(const char *name) 874 { 875 struct pci_conf_io pc; 876 struct pci_conf conf[1]; 877 struct pci_match_conf patterns[1]; 878 char *cp; 879 int fd; 880 881 fd = open(_PATH_DEVPCI, O_RDONLY, 0); 882 if (fd < 0) 883 err(1, "%s", _PATH_DEVPCI); 884 885 bzero(&pc, sizeof(struct pci_conf_io)); 886 pc.match_buf_len = sizeof(conf); 887 pc.matches = conf; 888 889 bzero(&patterns, sizeof(patterns)); 890 891 /* 892 * The pattern structure requires the unit to be split out from 893 * the driver name. Walk backwards from the end of the name to 894 * find the start of the unit. 895 */ 896 if (name[0] == '\0') 897 errx(1, "Empty device name"); 898 cp = strchr(name, '\0'); 899 assert(cp != NULL && cp != name); 900 cp--; 901 while (cp != name && isdigit(cp[-1])) 902 cp--; 903 if (cp == name || !isdigit(*cp)) 904 errx(1, "Invalid device name"); 905 if ((size_t)(cp - name) + 1 > sizeof(patterns[0].pd_name)) 906 errx(1, "Device name is too long"); 907 memcpy(patterns[0].pd_name, name, cp - name); 908 patterns[0].pd_unit = strtol(cp, &cp, 10); 909 if (*cp != '\0') 910 errx(1, "Invalid device name"); 911 patterns[0].flags = PCI_GETCONF_MATCH_NAME | PCI_GETCONF_MATCH_UNIT; 912 pc.num_patterns = 1; 913 pc.pat_buf_len = sizeof(patterns); 914 pc.patterns = patterns; 915 916 if (ioctl(fd, PCIOCGETCONF, &pc) == -1) 917 err(1, "ioctl(PCIOCGETCONF)"); 918 if (pc.status != PCI_GETCONF_LAST_DEVICE && 919 pc.status != PCI_GETCONF_MORE_DEVS) 920 errx(1, "error returned from PCIOCGETCONF ioctl"); 921 close(fd); 922 if (pc.num_matches == 0) 923 errx(1, "Device not found"); 924 return (conf[0].pc_sel); 925 } 926 927 static struct pcisel 928 parsesel(const char *str) 929 { 930 const char *ep; 931 char *eppos; 932 struct pcisel sel; 933 unsigned long selarr[4]; 934 int i; 935 936 ep = strchr(str, '@'); 937 if (ep != NULL) 938 ep++; 939 else 940 ep = str; 941 942 if (strncmp(ep, "pci", 3) == 0) { 943 ep += 3; 944 i = 0; 945 while (isdigit(*ep) && i < 4) { 946 selarr[i++] = strtoul(ep, &eppos, 10); 947 ep = eppos; 948 if (*ep == ':') 949 ep++; 950 } 951 if (i > 0 && *ep == '\0') { 952 sel.pc_func = (i > 2) ? selarr[--i] : 0; 953 sel.pc_dev = (i > 0) ? selarr[--i] : 0; 954 sel.pc_bus = (i > 0) ? selarr[--i] : 0; 955 sel.pc_domain = (i > 0) ? selarr[--i] : 0; 956 return (sel); 957 } 958 } 959 errx(1, "cannot parse selector %s", str); 960 } 961 962 static struct pcisel 963 getsel(const char *str) 964 { 965 966 /* 967 * No device names contain colons and selectors always contain 968 * at least one colon. 969 */ 970 if (strchr(str, ':') == NULL) 971 return (getdevice(str)); 972 else 973 return (parsesel(str)); 974 } 975 976 static void 977 readone(int fd, struct pcisel *sel, long reg, int width) 978 { 979 980 printf("%0*x", width*2, read_config(fd, sel, reg, width)); 981 } 982 983 static void 984 readit(const char *name, const char *reg, int width) 985 { 986 long rstart; 987 long rend; 988 long r; 989 char *end; 990 int i; 991 int fd; 992 struct pcisel sel; 993 994 fd = open(_PATH_DEVPCI, O_RDWR, 0); 995 if (fd < 0) 996 err(1, "%s", _PATH_DEVPCI); 997 998 rend = rstart = strtol(reg, &end, 0); 999 if (end && *end == ':') { 1000 end++; 1001 rend = strtol(end, (char **) 0, 0); 1002 } 1003 sel = getsel(name); 1004 for (i = 1, r = rstart; r <= rend; i++, r += width) { 1005 readone(fd, &sel, r, width); 1006 if (i && !(i % 8)) 1007 putchar(' '); 1008 putchar(i % (16/width) ? ' ' : '\n'); 1009 } 1010 if (i % (16/width) != 1) 1011 putchar('\n'); 1012 close(fd); 1013 } 1014 1015 static void 1016 writeit(const char *name, const char *reg, const char *data, int width) 1017 { 1018 int fd; 1019 struct pci_io pi; 1020 1021 pi.pi_sel = getsel(name); 1022 pi.pi_reg = strtoul(reg, (char **)0, 0); /* XXX error check */ 1023 pi.pi_width = width; 1024 pi.pi_data = strtoul(data, (char **)0, 0); /* XXX error check */ 1025 1026 fd = open(_PATH_DEVPCI, O_RDWR, 0); 1027 if (fd < 0) 1028 err(1, "%s", _PATH_DEVPCI); 1029 1030 if (ioctl(fd, PCIOCWRITE, &pi) < 0) 1031 err(1, "ioctl(PCIOCWRITE)"); 1032 close(fd); 1033 } 1034 1035 static void 1036 chkattached(const char *name) 1037 { 1038 int fd; 1039 struct pci_io pi; 1040 1041 pi.pi_sel = getsel(name); 1042 1043 fd = open(_PATH_DEVPCI, O_RDWR, 0); 1044 if (fd < 0) 1045 err(1, "%s", _PATH_DEVPCI); 1046 1047 if (ioctl(fd, PCIOCATTACHED, &pi) < 0) 1048 err(1, "ioctl(PCIOCATTACHED)"); 1049 1050 exitstatus = pi.pi_data ? 0 : 2; /* exit(2), if NOT attached */ 1051 printf("%s: %s%s\n", name, pi.pi_data == 0 ? "not " : "", "attached"); 1052 close(fd); 1053 } 1054 1055 static void 1056 dump_bar(const char *name, const char *reg, const char *bar_start, 1057 const char *bar_count, int width, int verbose) 1058 { 1059 struct pci_bar_mmap pbm; 1060 uint32_t *dd; 1061 uint16_t *dh; 1062 uint8_t *db; 1063 uint64_t *dx, a, start, count; 1064 char *el; 1065 size_t res; 1066 int fd; 1067 1068 start = 0; 1069 if (bar_start != NULL) { 1070 start = strtoul(bar_start, &el, 0); 1071 if (*el != '\0') 1072 errx(1, "Invalid bar start specification %s", 1073 bar_start); 1074 } 1075 count = 0; 1076 if (bar_count != NULL) { 1077 count = strtoul(bar_count, &el, 0); 1078 if (*el != '\0') 1079 errx(1, "Invalid count specification %s", 1080 bar_count); 1081 } 1082 1083 pbm.pbm_sel = getsel(name); 1084 pbm.pbm_reg = strtoul(reg, &el, 0); 1085 if (*reg == '\0' || *el != '\0') 1086 errx(1, "Invalid bar specification %s", reg); 1087 pbm.pbm_flags = 0; 1088 pbm.pbm_memattr = VM_MEMATTR_UNCACHEABLE; /* XXX */ 1089 1090 fd = open(_PATH_DEVPCI, O_RDWR, 0); 1091 if (fd < 0) 1092 err(1, "%s", _PATH_DEVPCI); 1093 1094 if (ioctl(fd, PCIOCBARMMAP, &pbm) < 0) 1095 err(1, "ioctl(PCIOCBARMMAP)"); 1096 1097 if (count == 0) 1098 count = pbm.pbm_bar_length / width; 1099 if (start + count < start || (start + count) * width < (uint64_t)width) 1100 errx(1, "(start + count) x width overflow"); 1101 if ((start + count) * width > pbm.pbm_bar_length) { 1102 if (start * width > pbm.pbm_bar_length) 1103 count = 0; 1104 else 1105 count = (pbm.pbm_bar_length - start * width) / width; 1106 } 1107 if (verbose) { 1108 fprintf(stderr, 1109 "Dumping pci%d:%d:%d:%d BAR %x mapped base %p " 1110 "off %#x length %#jx from %#jx count %#jx in %d-bytes\n", 1111 pbm.pbm_sel.pc_domain, pbm.pbm_sel.pc_bus, 1112 pbm.pbm_sel.pc_dev, pbm.pbm_sel.pc_func, 1113 pbm.pbm_reg, pbm.pbm_map_base, pbm.pbm_bar_off, 1114 pbm.pbm_bar_length, start, count, width); 1115 } 1116 switch (width) { 1117 case 1: 1118 db = (uint8_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + 1119 pbm.pbm_bar_off + start * width); 1120 for (a = 0; a < count; a += width, db++) { 1121 res = fwrite(db, width, 1, stdout); 1122 if (res != 1) { 1123 errx(1, "error writing to stdout"); 1124 break; 1125 } 1126 } 1127 break; 1128 case 2: 1129 dh = (uint16_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + 1130 pbm.pbm_bar_off + start * width); 1131 for (a = 0; a < count; a += width, dh++) { 1132 res = fwrite(dh, width, 1, stdout); 1133 if (res != 1) { 1134 errx(1, "error writing to stdout"); 1135 break; 1136 } 1137 } 1138 break; 1139 case 4: 1140 dd = (uint32_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + 1141 pbm.pbm_bar_off + start * width); 1142 for (a = 0; a < count; a += width, dd++) { 1143 res = fwrite(dd, width, 1, stdout); 1144 if (res != 1) { 1145 errx(1, "error writing to stdout"); 1146 break; 1147 } 1148 } 1149 break; 1150 case 8: 1151 dx = (uint64_t *)(uintptr_t)((uintptr_t)pbm.pbm_map_base + 1152 pbm.pbm_bar_off + start * width); 1153 for (a = 0; a < count; a += width, dx++) { 1154 res = fwrite(dx, width, 1, stdout); 1155 if (res != 1) { 1156 errx(1, "error writing to stdout"); 1157 break; 1158 } 1159 } 1160 break; 1161 default: 1162 errx(1, "invalid access width"); 1163 } 1164 1165 munmap((void *)pbm.pbm_map_base, pbm.pbm_map_length); 1166 close(fd); 1167 } 1168