Annotation of embedaddon/pciutils/lspci.c, revision 1.1
1.1 ! misho 1: /*
! 2: * The PCI Utilities -- List All PCI Devices
! 3: *
! 4: * Copyright (c) 1997--2008 Martin Mares <mj@ucw.cz>
! 5: *
! 6: * Can be freely distributed and used under the terms of the GNU GPL.
! 7: */
! 8:
! 9: #include <stdio.h>
! 10: #include <string.h>
! 11: #include <stdlib.h>
! 12: #include <stdarg.h>
! 13:
! 14: #include "lspci.h"
! 15:
! 16: /* Options */
! 17:
! 18: int verbose; /* Show detailed information */
! 19: static int opt_hex; /* Show contents of config space as hexadecimal numbers */
! 20: struct pci_filter filter; /* Device filter */
! 21: static int opt_tree; /* Show bus tree */
! 22: static int opt_machine; /* Generate machine-readable output */
! 23: static int opt_map_mode; /* Bus mapping mode enabled */
! 24: static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */
! 25: static int opt_kernel; /* Show kernel drivers */
! 26: static int opt_query_dns; /* Query the DNS (0=disabled, 1=enabled, 2=refresh cache) */
! 27: static int opt_query_all; /* Query the DNS for all entries */
! 28: char *opt_pcimap; /* Override path to Linux modules.pcimap */
! 29:
! 30: const char program_name[] = "lspci";
! 31:
! 32: static char options[] = "nvbxs:d:ti:mgp:qkMDQ" GENERIC_OPTIONS ;
! 33:
! 34: static char help_msg[] =
! 35: "Usage: lspci [<switches>]\n"
! 36: "\n"
! 37: "Basic display modes:\n"
! 38: "-mm\t\tProduce machine-readable output (single -m for an obsolete format)\n"
! 39: "-t\t\tShow bus tree\n"
! 40: "\n"
! 41: "Display options:\n"
! 42: "-v\t\tBe verbose (-vv for very verbose)\n"
! 43: #ifdef PCI_OS_LINUX
! 44: "-k\t\tShow kernel drivers handling each device\n"
! 45: #endif
! 46: "-x\t\tShow hex-dump of the standard part of the config space\n"
! 47: "-xxx\t\tShow hex-dump of the whole config space (dangerous; root only)\n"
! 48: "-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n"
! 49: "-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n"
! 50: "-D\t\tAlways show domain numbers\n"
! 51: "\n"
! 52: "Resolving of device ID's to names:\n"
! 53: "-n\t\tShow numeric ID's\n"
! 54: "-nn\t\tShow both textual and numeric ID's (names & numbers)\n"
! 55: #ifdef PCI_USE_DNS
! 56: "-q\t\tQuery the PCI ID database for unknown ID's via DNS\n"
! 57: "-qq\t\tAs above, but re-query locally cached entries\n"
! 58: "-Q\t\tQuery the PCI ID database for all ID's via DNS\n"
! 59: #endif
! 60: "\n"
! 61: "Selection of devices:\n"
! 62: "-s [[[[<domain>]:]<bus>]:][<slot>][.[<func>]]\tShow only devices in selected slots\n"
! 63: "-d [<vendor>]:[<device>]\t\t\tShow only devices with specified ID's\n"
! 64: "\n"
! 65: "Other options:\n"
! 66: "-i <file>\tUse specified ID database instead of %s\n"
! 67: #ifdef PCI_OS_LINUX
! 68: "-p <file>\tLook up kernel modules in a given file instead of default modules.pcimap\n"
! 69: #endif
! 70: "-M\t\tEnable `bus mapping' mode (dangerous; root only)\n"
! 71: "\n"
! 72: "PCI access options:\n"
! 73: GENERIC_HELP
! 74: ;
! 75:
! 76: /*** Our view of the PCI bus ***/
! 77:
! 78: struct pci_access *pacc;
! 79: struct device *first_dev;
! 80: static int seen_errors;
! 81:
! 82: int
! 83: config_fetch(struct device *d, unsigned int pos, unsigned int len)
! 84: {
! 85: unsigned int end = pos+len;
! 86: int result;
! 87:
! 88: while (pos < d->config_bufsize && len && d->present[pos])
! 89: pos++, len--;
! 90: while (pos+len <= d->config_bufsize && len && d->present[pos+len-1])
! 91: len--;
! 92: if (!len)
! 93: return 1;
! 94:
! 95: if (end > d->config_bufsize)
! 96: {
! 97: int orig_size = d->config_bufsize;
! 98: while (end > d->config_bufsize)
! 99: d->config_bufsize *= 2;
! 100: d->config = xrealloc(d->config, d->config_bufsize);
! 101: d->present = xrealloc(d->present, d->config_bufsize);
! 102: memset(d->present + orig_size, 0, d->config_bufsize - orig_size);
! 103: }
! 104: result = pci_read_block(d->dev, pos, d->config + pos, len);
! 105: if (result)
! 106: memset(d->present + pos, 1, len);
! 107: return result;
! 108: }
! 109:
! 110: struct device *
! 111: scan_device(struct pci_dev *p)
! 112: {
! 113: struct device *d;
! 114:
! 115: if (p->domain && !opt_domains)
! 116: opt_domains = 1;
! 117: if (!pci_filter_match(&filter, p))
! 118: return NULL;
! 119: d = xmalloc(sizeof(struct device));
! 120: memset(d, 0, sizeof(*d));
! 121: d->dev = p;
! 122: d->config_cached = d->config_bufsize = 64;
! 123: d->config = xmalloc(64);
! 124: d->present = xmalloc(64);
! 125: memset(d->present, 1, 64);
! 126: if (!pci_read_block(p, 0, d->config, 64))
! 127: {
! 128: fprintf(stderr, "lspci: Unable to read the standard configuration space header of device %04x:%02x:%02x.%d\n",
! 129: p->domain, p->bus, p->dev, p->func);
! 130: seen_errors++;
! 131: return NULL;
! 132: }
! 133: if ((d->config[PCI_HEADER_TYPE] & 0x7f) == PCI_HEADER_TYPE_CARDBUS)
! 134: {
! 135: /* For cardbus bridges, we need to fetch 64 bytes more to get the
! 136: * full standard header... */
! 137: if (config_fetch(d, 64, 64))
! 138: d->config_cached += 64;
! 139: }
! 140: pci_setup_cache(p, d->config, d->config_cached);
! 141: pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS | PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | PCI_FILL_PHYS_SLOT);
! 142: return d;
! 143: }
! 144:
! 145: static void
! 146: scan_devices(void)
! 147: {
! 148: struct device *d;
! 149: struct pci_dev *p;
! 150:
! 151: pci_scan_bus(pacc);
! 152: for (p=pacc->devices; p; p=p->next)
! 153: if (d = scan_device(p))
! 154: {
! 155: d->next = first_dev;
! 156: first_dev = d;
! 157: }
! 158: }
! 159:
! 160: /*** Config space accesses ***/
! 161:
! 162: static void
! 163: check_conf_range(struct device *d, unsigned int pos, unsigned int len)
! 164: {
! 165: while (len)
! 166: if (!d->present[pos])
! 167: die("Internal bug: Accessing non-read configuration byte at position %x", pos);
! 168: else
! 169: pos++, len--;
! 170: }
! 171:
! 172: byte
! 173: get_conf_byte(struct device *d, unsigned int pos)
! 174: {
! 175: check_conf_range(d, pos, 1);
! 176: return d->config[pos];
! 177: }
! 178:
! 179: word
! 180: get_conf_word(struct device *d, unsigned int pos)
! 181: {
! 182: check_conf_range(d, pos, 2);
! 183: return d->config[pos] | (d->config[pos+1] << 8);
! 184: }
! 185:
! 186: u32
! 187: get_conf_long(struct device *d, unsigned int pos)
! 188: {
! 189: check_conf_range(d, pos, 4);
! 190: return d->config[pos] |
! 191: (d->config[pos+1] << 8) |
! 192: (d->config[pos+2] << 16) |
! 193: (d->config[pos+3] << 24);
! 194: }
! 195:
! 196: /*** Sorting ***/
! 197:
! 198: static int
! 199: compare_them(const void *A, const void *B)
! 200: {
! 201: const struct pci_dev *a = (*(const struct device **)A)->dev;
! 202: const struct pci_dev *b = (*(const struct device **)B)->dev;
! 203:
! 204: if (a->domain < b->domain)
! 205: return -1;
! 206: if (a->domain > b->domain)
! 207: return 1;
! 208: if (a->bus < b->bus)
! 209: return -1;
! 210: if (a->bus > b->bus)
! 211: return 1;
! 212: if (a->dev < b->dev)
! 213: return -1;
! 214: if (a->dev > b->dev)
! 215: return 1;
! 216: if (a->func < b->func)
! 217: return -1;
! 218: if (a->func > b->func)
! 219: return 1;
! 220: return 0;
! 221: }
! 222:
! 223: static void
! 224: sort_them(void)
! 225: {
! 226: struct device **index, **h, **last_dev;
! 227: int cnt;
! 228: struct device *d;
! 229:
! 230: cnt = 0;
! 231: for (d=first_dev; d; d=d->next)
! 232: cnt++;
! 233: h = index = alloca(sizeof(struct device *) * cnt);
! 234: for (d=first_dev; d; d=d->next)
! 235: *h++ = d;
! 236: qsort(index, cnt, sizeof(struct device *), compare_them);
! 237: last_dev = &first_dev;
! 238: h = index;
! 239: while (cnt--)
! 240: {
! 241: *last_dev = *h;
! 242: last_dev = &(*h)->next;
! 243: h++;
! 244: }
! 245: *last_dev = NULL;
! 246: }
! 247:
! 248: /*** Normal output ***/
! 249:
! 250: static void
! 251: show_slot_name(struct device *d)
! 252: {
! 253: struct pci_dev *p = d->dev;
! 254:
! 255: if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2))
! 256: printf("%04x:", p->domain);
! 257: printf("%02x:%02x.%d", p->bus, p->dev, p->func);
! 258: }
! 259:
! 260: void
! 261: get_subid(struct device *d, word *subvp, word *subdp)
! 262: {
! 263: byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
! 264:
! 265: if (htype == PCI_HEADER_TYPE_NORMAL)
! 266: {
! 267: *subvp = get_conf_word(d, PCI_SUBSYSTEM_VENDOR_ID);
! 268: *subdp = get_conf_word(d, PCI_SUBSYSTEM_ID);
! 269: }
! 270: else if (htype == PCI_HEADER_TYPE_CARDBUS && d->config_cached >= 128)
! 271: {
! 272: *subvp = get_conf_word(d, PCI_CB_SUBSYSTEM_VENDOR_ID);
! 273: *subdp = get_conf_word(d, PCI_CB_SUBSYSTEM_ID);
! 274: }
! 275: else
! 276: *subvp = *subdp = 0xffff;
! 277: }
! 278:
! 279: static void
! 280: show_terse(struct device *d)
! 281: {
! 282: int c;
! 283: struct pci_dev *p = d->dev;
! 284: char classbuf[128], devbuf[128];
! 285:
! 286: show_slot_name(d);
! 287: printf(" %s: %s",
! 288: pci_lookup_name(pacc, classbuf, sizeof(classbuf),
! 289: PCI_LOOKUP_CLASS,
! 290: p->device_class),
! 291: pci_lookup_name(pacc, devbuf, sizeof(devbuf),
! 292: PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
! 293: p->vendor_id, p->device_id));
! 294: if (c = get_conf_byte(d, PCI_REVISION_ID))
! 295: printf(" (rev %02x)", c);
! 296: if (verbose)
! 297: {
! 298: char *x;
! 299: c = get_conf_byte(d, PCI_CLASS_PROG);
! 300: x = pci_lookup_name(pacc, devbuf, sizeof(devbuf),
! 301: PCI_LOOKUP_PROGIF | PCI_LOOKUP_NO_NUMBERS,
! 302: p->device_class, c);
! 303: if (c || x)
! 304: {
! 305: printf(" (prog-if %02x", c);
! 306: if (x)
! 307: printf(" [%s]", x);
! 308: putchar(')');
! 309: }
! 310: }
! 311: putchar('\n');
! 312:
! 313: if (verbose || opt_kernel)
! 314: {
! 315: word subsys_v, subsys_d;
! 316: char ssnamebuf[256];
! 317:
! 318: get_subid(d, &subsys_v, &subsys_d);
! 319: if (subsys_v && subsys_v != 0xffff)
! 320: printf("\tSubsystem: %s\n",
! 321: pci_lookup_name(pacc, ssnamebuf, sizeof(ssnamebuf),
! 322: PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR | PCI_LOOKUP_DEVICE,
! 323: p->vendor_id, p->device_id, subsys_v, subsys_d));
! 324: }
! 325: }
! 326:
! 327: /*** Verbose output ***/
! 328:
! 329: static void
! 330: show_size(pciaddr_t x)
! 331: {
! 332: static const char suffix[][2] = { "", "K", "M", "G", "T" };
! 333: unsigned i;
! 334: if (!x)
! 335: return;
! 336: for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++) {
! 337: if (x < 1024)
! 338: break;
! 339: x /= 1024;
! 340: }
! 341: printf(" [size=%u%s]", (unsigned)x, suffix[i]);
! 342: }
! 343:
! 344: static void
! 345: show_bases(struct device *d, int cnt)
! 346: {
! 347: struct pci_dev *p = d->dev;
! 348: word cmd = get_conf_word(d, PCI_COMMAND);
! 349: int i;
! 350: int virtual = 0;
! 351:
! 352: for (i=0; i<cnt; i++)
! 353: {
! 354: pciaddr_t pos = p->base_addr[i];
! 355: pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0;
! 356: u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
! 357: if (flg == 0xffffffff)
! 358: flg = 0;
! 359: if (!pos && !flg && !len)
! 360: continue;
! 361: if (verbose > 1)
! 362: printf("\tRegion %d: ", i);
! 363: else
! 364: putchar('\t');
! 365: if (pos && !flg) /* Reported by the OS, but not by the device */
! 366: {
! 367: printf("[virtual] ");
! 368: flg = pos;
! 369: virtual = 1;
! 370: }
! 371: if (flg & PCI_BASE_ADDRESS_SPACE_IO)
! 372: {
! 373: pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
! 374: printf("I/O ports at ");
! 375: if (a)
! 376: printf(PCIADDR_PORT_FMT, a);
! 377: else if (flg & PCI_BASE_ADDRESS_IO_MASK)
! 378: printf("<ignored>");
! 379: else
! 380: printf("<unassigned>");
! 381: if (!virtual && !(cmd & PCI_COMMAND_IO))
! 382: printf(" [disabled]");
! 383: }
! 384: else
! 385: {
! 386: int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
! 387: pciaddr_t a = pos & PCI_ADDR_MEM_MASK;
! 388: int done = 0;
! 389: u32 z = 0;
! 390:
! 391: printf("Memory at ");
! 392: if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
! 393: {
! 394: if (i >= cnt - 1)
! 395: {
! 396: printf("<invalid-64bit-slot>");
! 397: done = 1;
! 398: }
! 399: else
! 400: {
! 401: i++;
! 402: z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
! 403: }
! 404: }
! 405: if (!done)
! 406: {
! 407: if (a)
! 408: printf(PCIADDR_T_FMT, a);
! 409: else
! 410: printf(((flg & PCI_BASE_ADDRESS_MEM_MASK) || z) ? "<ignored>" : "<unassigned>");
! 411: }
! 412: printf(" (%s, %sprefetchable)",
! 413: (t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
! 414: (t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
! 415: (t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3",
! 416: (flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-");
! 417: if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
! 418: printf(" [disabled]");
! 419: }
! 420: show_size(len);
! 421: putchar('\n');
! 422: }
! 423: }
! 424:
! 425: static void
! 426: show_rom(struct device *d, int reg)
! 427: {
! 428: struct pci_dev *p = d->dev;
! 429: pciaddr_t rom = p->rom_base_addr;
! 430: pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0;
! 431: u32 flg = get_conf_long(d, reg);
! 432: word cmd = get_conf_word(d, PCI_COMMAND);
! 433: int virtual = 0;
! 434:
! 435: if (!rom && !flg && !len)
! 436: return;
! 437: putchar('\t');
! 438: if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK))
! 439: {
! 440: printf("[virtual] ");
! 441: flg = rom;
! 442: virtual = 1;
! 443: }
! 444: printf("Expansion ROM at ");
! 445: if (rom & PCI_ROM_ADDRESS_MASK)
! 446: printf(PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK);
! 447: else if (flg & PCI_ROM_ADDRESS_MASK)
! 448: printf("<ignored>");
! 449: else
! 450: printf("<unassigned>");
! 451: if (!(flg & PCI_ROM_ADDRESS_ENABLE))
! 452: printf(" [disabled]");
! 453: else if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
! 454: printf(" [disabled by cmd]");
! 455: show_size(len);
! 456: putchar('\n');
! 457: }
! 458:
! 459: static void
! 460: show_htype0(struct device *d)
! 461: {
! 462: show_bases(d, 6);
! 463: show_rom(d, PCI_ROM_ADDRESS);
! 464: show_caps(d);
! 465: }
! 466:
! 467: static void
! 468: show_htype1(struct device *d)
! 469: {
! 470: u32 io_base = get_conf_byte(d, PCI_IO_BASE);
! 471: u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
! 472: u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
! 473: u32 mem_base = get_conf_word(d, PCI_MEMORY_BASE);
! 474: u32 mem_limit = get_conf_word(d, PCI_MEMORY_LIMIT);
! 475: u32 mem_type = mem_base & PCI_MEMORY_RANGE_TYPE_MASK;
! 476: u32 pref_base = get_conf_word(d, PCI_PREF_MEMORY_BASE);
! 477: u32 pref_limit = get_conf_word(d, PCI_PREF_MEMORY_LIMIT);
! 478: u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK;
! 479: word sec_stat = get_conf_word(d, PCI_SEC_STATUS);
! 480: word brc = get_conf_word(d, PCI_BRIDGE_CONTROL);
! 481: int verb = verbose > 2;
! 482:
! 483: show_bases(d, 2);
! 484: printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
! 485: get_conf_byte(d, PCI_PRIMARY_BUS),
! 486: get_conf_byte(d, PCI_SECONDARY_BUS),
! 487: get_conf_byte(d, PCI_SUBORDINATE_BUS),
! 488: get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
! 489:
! 490: if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
! 491: (io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
! 492: printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
! 493: else
! 494: {
! 495: io_base = (io_base & PCI_IO_RANGE_MASK) << 8;
! 496: io_limit = (io_limit & PCI_IO_RANGE_MASK) << 8;
! 497: if (io_type == PCI_IO_RANGE_TYPE_32)
! 498: {
! 499: io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16);
! 500: io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16);
! 501: }
! 502: if (io_base <= io_limit || verb)
! 503: printf("\tI/O behind bridge: %08x-%08x\n", io_base, io_limit+0xfff);
! 504: }
! 505:
! 506: if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
! 507: mem_type)
! 508: printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
! 509: else
! 510: {
! 511: mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
! 512: mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
! 513: if (mem_base <= mem_limit || verb)
! 514: printf("\tMemory behind bridge: %08x-%08x\n", mem_base, mem_limit + 0xfffff);
! 515: }
! 516:
! 517: if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
! 518: (pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
! 519: printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
! 520: else
! 521: {
! 522: pref_base = (pref_base & PCI_PREF_RANGE_MASK) << 16;
! 523: pref_limit = (pref_limit & PCI_PREF_RANGE_MASK) << 16;
! 524: if (pref_base <= pref_limit || verb)
! 525: {
! 526: if (pref_type == PCI_PREF_RANGE_TYPE_32)
! 527: printf("\tPrefetchable memory behind bridge: %08x-%08x\n", pref_base, pref_limit + 0xfffff);
! 528: else
! 529: printf("\tPrefetchable memory behind bridge: %08x%08x-%08x%08x\n",
! 530: get_conf_long(d, PCI_PREF_BASE_UPPER32),
! 531: pref_base,
! 532: get_conf_long(d, PCI_PREF_LIMIT_UPPER32),
! 533: pref_limit + 0xfffff);
! 534: }
! 535: }
! 536:
! 537: if (verbose > 1)
! 538: printf("\tSecondary status: 66MHz%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c <SERR%c <PERR%c\n",
! 539: FLAG(sec_stat, PCI_STATUS_66MHZ),
! 540: FLAG(sec_stat, PCI_STATUS_FAST_BACK),
! 541: FLAG(sec_stat, PCI_STATUS_PARITY),
! 542: ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
! 543: ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
! 544: ((sec_stat & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
! 545: FLAG(sec_stat, PCI_STATUS_SIG_TARGET_ABORT),
! 546: FLAG(sec_stat, PCI_STATUS_REC_TARGET_ABORT),
! 547: FLAG(sec_stat, PCI_STATUS_REC_MASTER_ABORT),
! 548: FLAG(sec_stat, PCI_STATUS_SIG_SYSTEM_ERROR),
! 549: FLAG(sec_stat, PCI_STATUS_DETECTED_PARITY));
! 550:
! 551: show_rom(d, PCI_ROM_ADDRESS1);
! 552:
! 553: if (verbose > 1)
! 554: {
! 555: printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c MAbort%c >Reset%c FastB2B%c\n",
! 556: FLAG(brc, PCI_BRIDGE_CTL_PARITY),
! 557: FLAG(brc, PCI_BRIDGE_CTL_SERR),
! 558: FLAG(brc, PCI_BRIDGE_CTL_NO_ISA),
! 559: FLAG(brc, PCI_BRIDGE_CTL_VGA),
! 560: FLAG(brc, PCI_BRIDGE_CTL_MASTER_ABORT),
! 561: FLAG(brc, PCI_BRIDGE_CTL_BUS_RESET),
! 562: FLAG(brc, PCI_BRIDGE_CTL_FAST_BACK));
! 563: printf("\t\tPriDiscTmr%c SecDiscTmr%c DiscTmrStat%c DiscTmrSERREn%c\n",
! 564: FLAG(brc, PCI_BRIDGE_CTL_PRI_DISCARD_TIMER),
! 565: FLAG(brc, PCI_BRIDGE_CTL_SEC_DISCARD_TIMER),
! 566: FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_STATUS),
! 567: FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN));
! 568: }
! 569:
! 570: show_caps(d);
! 571: }
! 572:
! 573: static void
! 574: show_htype2(struct device *d)
! 575: {
! 576: int i;
! 577: word cmd = get_conf_word(d, PCI_COMMAND);
! 578: word brc = get_conf_word(d, PCI_CB_BRIDGE_CONTROL);
! 579: word exca;
! 580: int verb = verbose > 2;
! 581:
! 582: show_bases(d, 1);
! 583: printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
! 584: get_conf_byte(d, PCI_CB_PRIMARY_BUS),
! 585: get_conf_byte(d, PCI_CB_CARD_BUS),
! 586: get_conf_byte(d, PCI_CB_SUBORDINATE_BUS),
! 587: get_conf_byte(d, PCI_CB_LATENCY_TIMER));
! 588: for (i=0; i<2; i++)
! 589: {
! 590: int p = 8*i;
! 591: u32 base = get_conf_long(d, PCI_CB_MEMORY_BASE_0 + p);
! 592: u32 limit = get_conf_long(d, PCI_CB_MEMORY_LIMIT_0 + p);
! 593: limit = limit + 0xfff;
! 594: if (base <= limit || verb)
! 595: printf("\tMemory window %d: %08x-%08x%s%s\n", i, base, limit,
! 596: (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]",
! 597: (brc & (PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 << i)) ? " (prefetchable)" : "");
! 598: }
! 599: for (i=0; i<2; i++)
! 600: {
! 601: int p = 8*i;
! 602: u32 base = get_conf_long(d, PCI_CB_IO_BASE_0 + p);
! 603: u32 limit = get_conf_long(d, PCI_CB_IO_LIMIT_0 + p);
! 604: if (!(base & PCI_IO_RANGE_TYPE_32))
! 605: {
! 606: base &= 0xffff;
! 607: limit &= 0xffff;
! 608: }
! 609: base &= PCI_CB_IO_RANGE_MASK;
! 610: limit = (limit & PCI_CB_IO_RANGE_MASK) + 3;
! 611: if (base <= limit || verb)
! 612: printf("\tI/O window %d: %08x-%08x%s\n", i, base, limit,
! 613: (cmd & PCI_COMMAND_IO) ? "" : " [disabled]");
! 614: }
! 615:
! 616: if (get_conf_word(d, PCI_CB_SEC_STATUS) & PCI_STATUS_SIG_SYSTEM_ERROR)
! 617: printf("\tSecondary status: SERR\n");
! 618: if (verbose > 1)
! 619: printf("\tBridgeCtl: Parity%c SERR%c ISA%c VGA%c MAbort%c >Reset%c 16bInt%c PostWrite%c\n",
! 620: FLAG(brc, PCI_CB_BRIDGE_CTL_PARITY),
! 621: FLAG(brc, PCI_CB_BRIDGE_CTL_SERR),
! 622: FLAG(brc, PCI_CB_BRIDGE_CTL_ISA),
! 623: FLAG(brc, PCI_CB_BRIDGE_CTL_VGA),
! 624: FLAG(brc, PCI_CB_BRIDGE_CTL_MASTER_ABORT),
! 625: FLAG(brc, PCI_CB_BRIDGE_CTL_CB_RESET),
! 626: FLAG(brc, PCI_CB_BRIDGE_CTL_16BIT_INT),
! 627: FLAG(brc, PCI_CB_BRIDGE_CTL_POST_WRITES));
! 628:
! 629: if (d->config_cached < 128)
! 630: {
! 631: printf("\t<access denied to the rest>\n");
! 632: return;
! 633: }
! 634:
! 635: exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE);
! 636: if (exca)
! 637: printf("\t16-bit legacy interface ports at %04x\n", exca);
! 638: }
! 639:
! 640: static void
! 641: show_verbose(struct device *d)
! 642: {
! 643: struct pci_dev *p = d->dev;
! 644: word status = get_conf_word(d, PCI_STATUS);
! 645: word cmd = get_conf_word(d, PCI_COMMAND);
! 646: word class = p->device_class;
! 647: byte bist = get_conf_byte(d, PCI_BIST);
! 648: byte htype = get_conf_byte(d, PCI_HEADER_TYPE) & 0x7f;
! 649: byte latency = get_conf_byte(d, PCI_LATENCY_TIMER);
! 650: byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE);
! 651: byte max_lat, min_gnt;
! 652: byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
! 653: unsigned int irq = p->irq;
! 654:
! 655: show_terse(d);
! 656:
! 657: switch (htype)
! 658: {
! 659: case PCI_HEADER_TYPE_NORMAL:
! 660: if (class == PCI_CLASS_BRIDGE_PCI)
! 661: printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
! 662: max_lat = get_conf_byte(d, PCI_MAX_LAT);
! 663: min_gnt = get_conf_byte(d, PCI_MIN_GNT);
! 664: break;
! 665: case PCI_HEADER_TYPE_BRIDGE:
! 666: if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
! 667: printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
! 668: irq = int_pin = min_gnt = max_lat = 0;
! 669: break;
! 670: case PCI_HEADER_TYPE_CARDBUS:
! 671: if ((class >> 8) != PCI_BASE_CLASS_BRIDGE)
! 672: printf("\t!!! Invalid class %04x for header type %02x\n", class, htype);
! 673: min_gnt = max_lat = 0;
! 674: break;
! 675: default:
! 676: printf("\t!!! Unknown header type %02x\n", htype);
! 677: return;
! 678: }
! 679:
! 680: if (p->phy_slot)
! 681: printf("\tPhysical Slot: %s\n", p->phy_slot);
! 682:
! 683: if (verbose > 1)
! 684: {
! 685: printf("\tControl: I/O%c Mem%c BusMaster%c SpecCycle%c MemWINV%c VGASnoop%c ParErr%c Stepping%c SERR%c FastB2B%c DisINTx%c\n",
! 686: FLAG(cmd, PCI_COMMAND_IO),
! 687: FLAG(cmd, PCI_COMMAND_MEMORY),
! 688: FLAG(cmd, PCI_COMMAND_MASTER),
! 689: FLAG(cmd, PCI_COMMAND_SPECIAL),
! 690: FLAG(cmd, PCI_COMMAND_INVALIDATE),
! 691: FLAG(cmd, PCI_COMMAND_VGA_PALETTE),
! 692: FLAG(cmd, PCI_COMMAND_PARITY),
! 693: FLAG(cmd, PCI_COMMAND_WAIT),
! 694: FLAG(cmd, PCI_COMMAND_SERR),
! 695: FLAG(cmd, PCI_COMMAND_FAST_BACK),
! 696: FLAG(cmd, PCI_COMMAND_DISABLE_INTx));
! 697: printf("\tStatus: Cap%c 66MHz%c UDF%c FastB2B%c ParErr%c DEVSEL=%s >TAbort%c <TAbort%c <MAbort%c >SERR%c <PERR%c INTx%c\n",
! 698: FLAG(status, PCI_STATUS_CAP_LIST),
! 699: FLAG(status, PCI_STATUS_66MHZ),
! 700: FLAG(status, PCI_STATUS_UDF),
! 701: FLAG(status, PCI_STATUS_FAST_BACK),
! 702: FLAG(status, PCI_STATUS_PARITY),
! 703: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
! 704: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
! 705: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??",
! 706: FLAG(status, PCI_STATUS_SIG_TARGET_ABORT),
! 707: FLAG(status, PCI_STATUS_REC_TARGET_ABORT),
! 708: FLAG(status, PCI_STATUS_REC_MASTER_ABORT),
! 709: FLAG(status, PCI_STATUS_SIG_SYSTEM_ERROR),
! 710: FLAG(status, PCI_STATUS_DETECTED_PARITY),
! 711: FLAG(status, PCI_STATUS_INTx));
! 712: if (cmd & PCI_COMMAND_MASTER)
! 713: {
! 714: printf("\tLatency: %d", latency);
! 715: if (min_gnt || max_lat)
! 716: {
! 717: printf(" (");
! 718: if (min_gnt)
! 719: printf("%dns min", min_gnt*250);
! 720: if (min_gnt && max_lat)
! 721: printf(", ");
! 722: if (max_lat)
! 723: printf("%dns max", max_lat*250);
! 724: putchar(')');
! 725: }
! 726: if (cache_line)
! 727: printf(", Cache Line Size: %d bytes", cache_line * 4);
! 728: putchar('\n');
! 729: }
! 730: if (int_pin || irq)
! 731: printf("\tInterrupt: pin %c routed to IRQ " PCIIRQ_FMT "\n",
! 732: (int_pin ? 'A' + int_pin - 1 : '?'), irq);
! 733: }
! 734: else
! 735: {
! 736: printf("\tFlags: ");
! 737: if (cmd & PCI_COMMAND_MASTER)
! 738: printf("bus master, ");
! 739: if (cmd & PCI_COMMAND_VGA_PALETTE)
! 740: printf("VGA palette snoop, ");
! 741: if (cmd & PCI_COMMAND_WAIT)
! 742: printf("stepping, ");
! 743: if (cmd & PCI_COMMAND_FAST_BACK)
! 744: printf("fast Back2Back, ");
! 745: if (status & PCI_STATUS_66MHZ)
! 746: printf("66MHz, ");
! 747: if (status & PCI_STATUS_UDF)
! 748: printf("user-definable features, ");
! 749: printf("%s devsel",
! 750: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_SLOW) ? "slow" :
! 751: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_MEDIUM) ? "medium" :
! 752: ((status & PCI_STATUS_DEVSEL_MASK) == PCI_STATUS_DEVSEL_FAST) ? "fast" : "??");
! 753: if (cmd & PCI_COMMAND_MASTER)
! 754: printf(", latency %d", latency);
! 755: if (irq)
! 756: printf(", IRQ " PCIIRQ_FMT, irq);
! 757: putchar('\n');
! 758: }
! 759:
! 760: if (bist & PCI_BIST_CAPABLE)
! 761: {
! 762: if (bist & PCI_BIST_START)
! 763: printf("\tBIST is running\n");
! 764: else
! 765: printf("\tBIST result: %02x\n", bist & PCI_BIST_CODE_MASK);
! 766: }
! 767:
! 768: switch (htype)
! 769: {
! 770: case PCI_HEADER_TYPE_NORMAL:
! 771: show_htype0(d);
! 772: break;
! 773: case PCI_HEADER_TYPE_BRIDGE:
! 774: show_htype1(d);
! 775: break;
! 776: case PCI_HEADER_TYPE_CARDBUS:
! 777: show_htype2(d);
! 778: break;
! 779: }
! 780: }
! 781:
! 782: /*** Machine-readable dumps ***/
! 783:
! 784: static void
! 785: show_hex_dump(struct device *d)
! 786: {
! 787: unsigned int i, cnt;
! 788:
! 789: cnt = d->config_cached;
! 790: if (opt_hex >= 3 && config_fetch(d, cnt, 256-cnt))
! 791: {
! 792: cnt = 256;
! 793: if (opt_hex >= 4 && config_fetch(d, 256, 4096-256))
! 794: cnt = 4096;
! 795: }
! 796:
! 797: for (i=0; i<cnt; i++)
! 798: {
! 799: if (! (i & 15))
! 800: printf("%02x:", i);
! 801: printf(" %02x", get_conf_byte(d, i));
! 802: if ((i & 15) == 15)
! 803: putchar('\n');
! 804: }
! 805: }
! 806:
! 807: static void
! 808: print_shell_escaped(char *c)
! 809: {
! 810: printf(" \"");
! 811: while (*c)
! 812: {
! 813: if (*c == '"' || *c == '\\')
! 814: putchar('\\');
! 815: putchar(*c++);
! 816: }
! 817: putchar('"');
! 818: }
! 819:
! 820: static void
! 821: show_machine(struct device *d)
! 822: {
! 823: struct pci_dev *p = d->dev;
! 824: int c;
! 825: word sv_id, sd_id;
! 826: char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
! 827:
! 828: get_subid(d, &sv_id, &sd_id);
! 829:
! 830: if (verbose)
! 831: {
! 832: printf((opt_machine >= 2) ? "Slot:\t" : "Device:\t");
! 833: show_slot_name(d);
! 834: putchar('\n');
! 835: printf("Class:\t%s\n",
! 836: pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
! 837: printf("Vendor:\t%s\n",
! 838: pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
! 839: printf("Device:\t%s\n",
! 840: pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
! 841: if (sv_id && sv_id != 0xffff)
! 842: {
! 843: printf("SVendor:\t%s\n",
! 844: pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
! 845: printf("SDevice:\t%s\n",
! 846: pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
! 847: }
! 848: if (p->phy_slot)
! 849: printf("PhySlot:\t%s\n", p->phy_slot);
! 850: if (c = get_conf_byte(d, PCI_REVISION_ID))
! 851: printf("Rev:\t%02x\n", c);
! 852: if (c = get_conf_byte(d, PCI_CLASS_PROG))
! 853: printf("ProgIf:\t%02x\n", c);
! 854: if (opt_kernel)
! 855: show_kernel_machine(d);
! 856: }
! 857: else
! 858: {
! 859: show_slot_name(d);
! 860: print_shell_escaped(pci_lookup_name(pacc, classbuf, sizeof(classbuf), PCI_LOOKUP_CLASS, p->device_class));
! 861: print_shell_escaped(pci_lookup_name(pacc, vendbuf, sizeof(vendbuf), PCI_LOOKUP_VENDOR, p->vendor_id, p->device_id));
! 862: print_shell_escaped(pci_lookup_name(pacc, devbuf, sizeof(devbuf), PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id));
! 863: if (c = get_conf_byte(d, PCI_REVISION_ID))
! 864: printf(" -r%02x", c);
! 865: if (c = get_conf_byte(d, PCI_CLASS_PROG))
! 866: printf(" -p%02x", c);
! 867: if (sv_id && sv_id != 0xffff)
! 868: {
! 869: print_shell_escaped(pci_lookup_name(pacc, svbuf, sizeof(svbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_VENDOR, sv_id));
! 870: print_shell_escaped(pci_lookup_name(pacc, sdbuf, sizeof(sdbuf), PCI_LOOKUP_SUBSYSTEM | PCI_LOOKUP_DEVICE, p->vendor_id, p->device_id, sv_id, sd_id));
! 871: }
! 872: else
! 873: printf(" \"\" \"\"");
! 874: putchar('\n');
! 875: }
! 876: }
! 877:
! 878: /*** Main show function ***/
! 879:
! 880: void
! 881: show_device(struct device *d)
! 882: {
! 883: if (opt_machine)
! 884: show_machine(d);
! 885: else
! 886: {
! 887: if (verbose)
! 888: show_verbose(d);
! 889: else
! 890: show_terse(d);
! 891: if (opt_kernel || verbose)
! 892: show_kernel(d);
! 893: }
! 894: if (opt_hex)
! 895: show_hex_dump(d);
! 896: if (verbose || opt_hex)
! 897: putchar('\n');
! 898: }
! 899:
! 900: static void
! 901: show(void)
! 902: {
! 903: struct device *d;
! 904:
! 905: for (d=first_dev; d; d=d->next)
! 906: show_device(d);
! 907: }
! 908:
! 909: /* Main */
! 910:
! 911: int
! 912: main(int argc, char **argv)
! 913: {
! 914: int i;
! 915: char *msg;
! 916:
! 917: if (argc == 2 && !strcmp(argv[1], "--version"))
! 918: {
! 919: puts("lspci version " PCIUTILS_VERSION);
! 920: return 0;
! 921: }
! 922:
! 923: pacc = pci_alloc();
! 924: pacc->error = die;
! 925: pci_filter_init(pacc, &filter);
! 926:
! 927: while ((i = getopt(argc, argv, options)) != -1)
! 928: switch (i)
! 929: {
! 930: case 'n':
! 931: pacc->numeric_ids++;
! 932: break;
! 933: case 'v':
! 934: verbose++;
! 935: break;
! 936: case 'b':
! 937: pacc->buscentric = 1;
! 938: break;
! 939: case 's':
! 940: if (msg = pci_filter_parse_slot(&filter, optarg))
! 941: die("-s: %s", msg);
! 942: break;
! 943: case 'd':
! 944: if (msg = pci_filter_parse_id(&filter, optarg))
! 945: die("-d: %s", msg);
! 946: break;
! 947: case 'x':
! 948: opt_hex++;
! 949: break;
! 950: case 't':
! 951: opt_tree++;
! 952: break;
! 953: case 'i':
! 954: pci_set_name_list_path(pacc, optarg, 0);
! 955: break;
! 956: case 'm':
! 957: opt_machine++;
! 958: break;
! 959: case 'p':
! 960: opt_pcimap = optarg;
! 961: break;
! 962: #ifdef PCI_OS_LINUX
! 963: case 'k':
! 964: opt_kernel++;
! 965: break;
! 966: #endif
! 967: case 'M':
! 968: opt_map_mode++;
! 969: break;
! 970: case 'D':
! 971: opt_domains = 2;
! 972: break;
! 973: #ifdef PCI_USE_DNS
! 974: case 'q':
! 975: opt_query_dns++;
! 976: break;
! 977: case 'Q':
! 978: opt_query_all = 1;
! 979: break;
! 980: #else
! 981: case 'q':
! 982: case 'Q':
! 983: die("DNS queries are not available in this version");
! 984: #endif
! 985: default:
! 986: if (parse_generic_option(i, pacc, optarg))
! 987: break;
! 988: bad:
! 989: fprintf(stderr, help_msg, pacc->id_file_name);
! 990: return 1;
! 991: }
! 992: if (optind < argc)
! 993: goto bad;
! 994:
! 995: if (opt_query_dns)
! 996: {
! 997: pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK;
! 998: if (opt_query_dns > 1)
! 999: pacc->id_lookup_mode |= PCI_LOOKUP_REFRESH_CACHE;
! 1000: }
! 1001: if (opt_query_all)
! 1002: pacc->id_lookup_mode |= PCI_LOOKUP_NETWORK | PCI_LOOKUP_SKIP_LOCAL;
! 1003:
! 1004: pci_init(pacc);
! 1005: if (opt_map_mode)
! 1006: map_the_bus();
! 1007: else
! 1008: {
! 1009: scan_devices();
! 1010: sort_them();
! 1011: if (opt_tree)
! 1012: show_forest();
! 1013: else
! 1014: show();
! 1015: }
! 1016: pci_cleanup(pacc);
! 1017:
! 1018: return (seen_errors ? 2 : 0);
! 1019: }
FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>