X-Git-Url: http://mj.ucw.cz/gitweb/?a=blobdiff_plain;f=lspci.c;h=7418b072c0c23783e5763a4b8091b9cc24d6f793;hb=25f2e4db6ecad1868302bc27d5b1ec7d74a59c19;hp=bca1ccbca3b3d3e9a3aaecbf1ca57987ef553065;hpb=a30f08396bd651989c0f3ca98805acc731e07213;p=pciutils.git diff --git a/lspci.c b/lspci.c index bca1ccb..7418b07 100644 --- a/lspci.c +++ b/lspci.c @@ -1,7 +1,7 @@ /* * The PCI Utilities -- List All PCI Devices * - * Copyright (c) 1997--2008 Martin Mares + * Copyright (c) 1997--2018 Martin Mares * * Can be freely distributed and used under the terms of the GNU GPL. */ @@ -18,7 +18,9 @@ int verbose; /* Show detailed information */ static int opt_hex; /* Show contents of config space as hexadecimal numbers */ struct pci_filter filter; /* Device filter */ +static int opt_filter; /* Any filter was given */ static int opt_tree; /* Show bus tree */ +static int opt_path; /* Show bridge path */ static int opt_machine; /* Generate machine-readable output */ static int opt_map_mode; /* Bus mapping mode enabled */ static int opt_domains; /* Show domain numbers (0=disabled, 1=auto-detected, 2=requested) */ @@ -29,7 +31,7 @@ char *opt_pcimap; /* Override path to Linux modules.pcimap */ const char program_name[] = "lspci"; -static char options[] = "nvbxs:d:ti:mgp:qkMDQ" GENERIC_OPTIONS ; +static char options[] = "nvbxs:d:tPi:mgp:qkMDQ" GENERIC_OPTIONS ; static char help_msg[] = "Usage: lspci []\n" @@ -39,7 +41,7 @@ static char help_msg[] = "-t\t\tShow bus tree\n" "\n" "Display options:\n" -"-v\t\tBe verbose (-vv for very verbose)\n" +"-v\t\tBe verbose (-vv or -vvv for higher verbosity)\n" #ifdef PCI_OS_LINUX "-k\t\tShow kernel drivers handling each device\n" #endif @@ -48,6 +50,8 @@ static char help_msg[] = "-xxxx\t\tShow hex-dump of the 4096-byte extended config space (root only)\n" "-b\t\tBus-centric view (addresses and IRQ's as seen by the bus)\n" "-D\t\tAlways show domain numbers\n" +"-P\t\tDisplay bridge path in addition to bus and device number\n" +"-PP\t\tDisplay bus path in addition to bus and device number\n" "\n" "Resolving of device ID's to names:\n" "-n\t\tShow numeric ID's\n" @@ -60,7 +64,7 @@ static char help_msg[] = "\n" "Selection of devices:\n" "-s [[[[]:]]:][][.[]]\tShow only devices in selected slots\n" -"-d []:[]\t\t\tShow only devices with specified ID's\n" +"-d []:[][:]\t\tShow only devices with specified ID's\n" "\n" "Other options:\n" "-i \tUse specified ID database instead of %s\n" @@ -78,6 +82,7 @@ GENERIC_HELP struct pci_access *pacc; struct device *first_dev; static int seen_errors; +static int need_topology; int config_fetch(struct device *d, unsigned int pos, unsigned int len) @@ -114,7 +119,7 @@ scan_device(struct pci_dev *p) if (p->domain && !opt_domains) opt_domains = 1; - if (!pci_filter_match(&filter, p)) + if (!pci_filter_match(&filter, p) && !need_topology) return NULL; d = xmalloc(sizeof(struct device)); memset(d, 0, sizeof(*d)); @@ -138,7 +143,7 @@ scan_device(struct pci_dev *p) d->config_cached += 64; } pci_setup_cache(p, d->config, d->config_cached); - 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); + pci_fill_info(p, PCI_FILL_IDENT | PCI_FILL_CLASS); return d; } @@ -247,6 +252,29 @@ sort_them(void) /*** Normal output ***/ +static void +show_slot_path(struct device *d) +{ + struct pci_dev *p = d->dev; + + if (opt_path) + { + struct bus *bus = d->parent_bus; + struct bridge *br = bus->parent_bridge; + + if (br && br->br_dev) + { + show_slot_path(br->br_dev); + if (opt_path > 1) + printf("/%02x:%02x.%d", p->bus, p->dev, p->func); + else + printf("/%02x.%d", p->dev, p->func); + return; + } + } + printf("%02x:%02x.%d", p->bus, p->dev, p->func); +} + static void show_slot_name(struct device *d) { @@ -254,7 +282,7 @@ show_slot_name(struct device *d) if (!opt_machine ? opt_domains : (p->domain || opt_domains >= 2)) printf("%04x:", p->domain); - printf("%02x:%02x.%d", p->bus, p->dev, p->func); + show_slot_path(d); } void @@ -315,6 +343,10 @@ show_terse(struct device *d) word subsys_v, subsys_d; char ssnamebuf[256]; + pci_fill_info(p, PCI_FILL_LABEL); + + if (p->label) + printf("\tDeviceName: %s", p->label); get_subid(d, &subsys_v, &subsys_d); if (subsys_v && subsys_v != 0xffff) printf("\tSubsystem: %s\n", @@ -327,20 +359,40 @@ show_terse(struct device *d) /*** Verbose output ***/ static void -show_size(pciaddr_t x) +show_size(u64 x) { static const char suffix[][2] = { "", "K", "M", "G", "T" }; unsigned i; if (!x) return; for (i = 0; i < (sizeof(suffix) / sizeof(*suffix) - 1); i++) { - if (x < 1024) + if (x % 1024) break; x /= 1024; } printf(" [size=%u%s]", (unsigned)x, suffix[i]); } +static void +show_range(char *prefix, u64 base, u64 limit, int is_64bit) +{ + if (base > limit && verbose < 3) + { + printf("%s: None\n", prefix); + return; + } + printf("%s: ", prefix); + if (is_64bit) + printf("%016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit); + else + printf("%08x-%08x", (unsigned) base, (unsigned) limit); + if (base <= limit) + show_size(limit - base + 1); + else + printf(" [empty]"); + putchar('\n'); +} + static void show_bases(struct device *d, int cnt) { @@ -353,6 +405,7 @@ show_bases(struct device *d, int cnt) { pciaddr_t pos = p->base_addr[i]; pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->size[i] : 0; + pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->flags[i] : 0; u32 flg = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i); if (flg == 0xffffffff) flg = 0; @@ -362,8 +415,11 @@ show_bases(struct device *d, int cnt) printf("\tRegion %d: ", i); else putchar('\t'); - if (pos && !flg) /* Reported by the OS, but not by the device */ + if (ioflg & PCI_IORESOURCE_PCI_EA_BEI) + printf("[enhanced] "); + else if (pos && !(flg & ((flg & PCI_BASE_ADDRESS_SPACE_IO) ? PCI_BASE_ADDRESS_IO_MASK : PCI_BASE_ADDRESS_MEM_MASK))) { + /* Reported by the OS, but not by the device */ printf("[virtual] "); flg = pos; virtual = 1; @@ -372,7 +428,7 @@ show_bases(struct device *d, int cnt) { pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK; printf("I/O ports at "); - if (a) + if (a || (cmd & PCI_COMMAND_IO)) printf(PCIADDR_PORT_FMT, a); else if (flg & PCI_BASE_ADDRESS_IO_MASK) printf(""); @@ -428,6 +484,7 @@ show_rom(struct device *d, int reg) struct pci_dev *p = d->dev; pciaddr_t rom = p->rom_base_addr; pciaddr_t len = (p->known_fields & PCI_FILL_SIZES) ? p->rom_size : 0; + pciaddr_t ioflg = (p->known_fields & PCI_FILL_IO_FLAGS) ? p->rom_flags : 0; u32 flg = get_conf_long(d, reg); word cmd = get_conf_word(d, PCI_COMMAND); int virtual = 0; @@ -435,7 +492,9 @@ show_rom(struct device *d, int reg) if (!rom && !flg && !len) return; putchar('\t'); - if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK)) + if (ioflg & PCI_IORESOURCE_PCI_EA_BEI) + printf("[enhanced] "); + else if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK)) { printf("[virtual] "); flg = rom; @@ -461,7 +520,7 @@ show_htype0(struct device *d) { show_bases(d, 6); show_rom(d, PCI_ROM_ADDRESS); - show_caps(d); + show_caps(d, PCI_CAPABILITY_LIST); } static void @@ -478,7 +537,6 @@ show_htype1(struct device *d) u32 pref_type = pref_base & PCI_PREF_RANGE_TYPE_MASK; word sec_stat = get_conf_word(d, PCI_SEC_STATUS); word brc = get_conf_word(d, PCI_BRIDGE_CONTROL); - int verb = verbose > 2; show_bases(d, 2); printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n", @@ -499,8 +557,7 @@ show_htype1(struct device *d) io_base |= (get_conf_word(d, PCI_IO_BASE_UPPER16) << 16); io_limit |= (get_conf_word(d, PCI_IO_LIMIT_UPPER16) << 16); } - if (io_base <= io_limit || verb) - printf("\tI/O behind bridge: %08x-%08x\n", io_base, io_limit+0xfff); + show_range("\tI/O behind bridge", io_base, io_limit+0xfff, 0); } if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) || @@ -510,8 +567,7 @@ show_htype1(struct device *d) { mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16; mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16; - if (mem_base <= mem_limit || verb) - printf("\tMemory behind bridge: %08x-%08x\n", mem_base, mem_limit + 0xfffff); + show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 0); } if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) || @@ -519,19 +575,14 @@ show_htype1(struct device *d) printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit); else { - pref_base = (pref_base & PCI_PREF_RANGE_MASK) << 16; - pref_limit = (pref_limit & PCI_PREF_RANGE_MASK) << 16; - if (pref_base <= pref_limit || verb) + u64 pref_base_64 = (pref_base & PCI_PREF_RANGE_MASK) << 16; + u64 pref_limit_64 = (pref_limit & PCI_PREF_RANGE_MASK) << 16; + if (pref_type == PCI_PREF_RANGE_TYPE_64) { - if (pref_type == PCI_PREF_RANGE_TYPE_32) - printf("\tPrefetchable memory behind bridge: %08x-%08x\n", pref_base, pref_limit + 0xfffff); - else - printf("\tPrefetchable memory behind bridge: %08x%08x-%08x%08x\n", - get_conf_long(d, PCI_PREF_BASE_UPPER32), - pref_base, - get_conf_long(d, PCI_PREF_LIMIT_UPPER32), - pref_limit + 0xfffff); + pref_base_64 |= (u64) get_conf_long(d, PCI_PREF_BASE_UPPER32) << 32; + pref_limit_64 |= (u64) get_conf_long(d, PCI_PREF_LIMIT_UPPER32) << 32; } + show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64 + 0xfffff, (pref_type == PCI_PREF_RANGE_TYPE_64)); } if (verbose > 1) @@ -552,11 +603,12 @@ show_htype1(struct device *d) if (verbose > 1) { - printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c MAbort%c >Reset%c FastB2B%c\n", + printf("\tBridgeCtl: Parity%c SERR%c NoISA%c VGA%c VGA16%c MAbort%c >Reset%c FastB2B%c\n", FLAG(brc, PCI_BRIDGE_CTL_PARITY), FLAG(brc, PCI_BRIDGE_CTL_SERR), FLAG(brc, PCI_BRIDGE_CTL_NO_ISA), FLAG(brc, PCI_BRIDGE_CTL_VGA), + FLAG(brc, PCI_BRIDGE_CTL_VGA_16BIT), FLAG(brc, PCI_BRIDGE_CTL_MASTER_ABORT), FLAG(brc, PCI_BRIDGE_CTL_BUS_RESET), FLAG(brc, PCI_BRIDGE_CTL_FAST_BACK)); @@ -567,7 +619,7 @@ show_htype1(struct device *d) FLAG(brc, PCI_BRIDGE_CTL_DISCARD_TIMER_SERR_EN)); } - show_caps(d); + show_caps(d, PCI_CAPABILITY_LIST); } static void @@ -590,7 +642,8 @@ show_htype2(struct device *d) int p = 8*i; u32 base = get_conf_long(d, PCI_CB_MEMORY_BASE_0 + p); u32 limit = get_conf_long(d, PCI_CB_MEMORY_LIMIT_0 + p); - if (limit > base || verb) + limit = limit + 0xfff; + if (base <= limit || verb) printf("\tMemory window %d: %08x-%08x%s%s\n", i, base, limit, (cmd & PCI_COMMAND_MEMORY) ? "" : " [disabled]", (brc & (PCI_CB_BRIDGE_CTL_PREFETCH_MEM0 << i)) ? " (prefetchable)" : ""); @@ -634,6 +687,7 @@ show_htype2(struct device *d) exca = get_conf_word(d, PCI_CB_LEGACY_MODE_BASE); if (exca) printf("\t16-bit legacy interface ports at %04x\n", exca); + show_caps(d, PCI_CB_CAPABILITY_LIST); } static void @@ -649,10 +703,15 @@ show_verbose(struct device *d) byte cache_line = get_conf_byte(d, PCI_CACHE_LINE_SIZE); byte max_lat, min_gnt; byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN); - unsigned int irq = p->irq; + unsigned int irq; + char *dt_node; show_terse(d); + pci_fill_info(p, PCI_FILL_IRQ | PCI_FILL_BASES | PCI_FILL_ROM_BASE | PCI_FILL_SIZES | + PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE); + irq = p->irq; + switch (htype) { case PCI_HEADER_TYPE_NORMAL: @@ -664,7 +723,7 @@ show_verbose(struct device *d) case PCI_HEADER_TYPE_BRIDGE: if ((class >> 8) != PCI_BASE_CLASS_BRIDGE) printf("\t!!! Invalid class %04x for header type %02x\n", class, htype); - irq = int_pin = min_gnt = max_lat = 0; + min_gnt = max_lat = 0; break; case PCI_HEADER_TYPE_CARDBUS: if ((class >> 8) != PCI_BASE_CLASS_BRIDGE) @@ -679,6 +738,9 @@ show_verbose(struct device *d) if (p->phy_slot) printf("\tPhysical Slot: %s\n", p->phy_slot); + if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE)) + printf("\tDevice tree node: %s\n", dt_node); + if (verbose > 1) { 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", @@ -729,6 +791,8 @@ show_verbose(struct device *d) if (int_pin || irq) printf("\tInterrupt: pin %c routed to IRQ " PCIIRQ_FMT "\n", (int_pin ? 'A' + int_pin - 1 : '?'), irq); + if (p->numa_node != -1) + printf("\tNUMA node: %d\n", p->numa_node); } else { @@ -753,6 +817,8 @@ show_verbose(struct device *d) printf(", latency %d", latency); if (irq) printf(", IRQ " PCIIRQ_FMT, irq); + if (p->numa_node != -1) + printf(", NUMA node %d", p->numa_node); putchar('\n'); } @@ -823,11 +889,13 @@ show_machine(struct device *d) int c; word sv_id, sd_id; char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128]; + char *dt_node; get_subid(d, &sv_id, &sd_id); if (verbose) { + pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE); printf((opt_machine >= 2) ? "Slot:\t" : "Device:\t"); show_slot_name(d); putchar('\n'); @@ -852,6 +920,10 @@ show_machine(struct device *d) printf("ProgIf:\t%02x\n", c); if (opt_kernel) show_kernel_machine(d); + if (p->numa_node != -1) + printf("NUMANode:\t%d\n", p->numa_node); + if (dt_node = pci_get_string_property(p, PCI_FILL_DT_NODE)) + printf("DTNode:\t%s\n", dt_node); } else { @@ -902,7 +974,8 @@ show(void) struct device *d; for (d=first_dev; d; d=d->next) - show_device(d); + if (pci_filter_match(&filter, d->dev)) + show_device(d); } /* Main */ @@ -938,16 +1011,23 @@ main(int argc, char **argv) case 's': if (msg = pci_filter_parse_slot(&filter, optarg)) die("-s: %s", msg); + opt_filter = 1; break; case 'd': if (msg = pci_filter_parse_id(&filter, optarg)) die("-d: %s", msg); + opt_filter = 1; break; case 'x': opt_hex++; break; + case 'P': + opt_path++; + need_topology = 1; + break; case 't': opt_tree++; + need_topology = 1; break; case 'i': pci_set_name_list_path(pacc, optarg, 0); @@ -1002,16 +1082,23 @@ main(int argc, char **argv) pci_init(pacc); if (opt_map_mode) - map_the_bus(); + { + if (need_topology) + die("Bus mapping mode does not recognize bus topology"); + map_the_bus(); + } else { scan_devices(); sort_them(); + if (need_topology) + grow_tree(); if (opt_tree) - show_forest(); + show_forest(opt_filter ? &filter : NULL); else show(); } + show_kernel_cleanup(); pci_cleanup(pacc); return (seen_errors ? 2 : 0);