/*
* The PCI Utilities -- List All PCI Devices
*
- * Copyright (c) 1997--2018 Martin Mares <mj@ucw.cz>
+ * Copyright (c) 1997--2020 Martin Mares <mj@ucw.cz>
*
* Can be freely distributed and used under the terms of the GNU GPL.
*/
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 */
"-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
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)
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));
static void
show_range(char *prefix, u64 base, u64 limit, int is_64bit)
{
- if (base > limit)
+ printf("%s:", prefix);
+ if (base <= limit || verbose > 2)
{
- if (!verbose)
- return;
- else if (verbose < 3)
- {
- printf("%s: None\n", prefix);
- return;
- }
+ if (is_64bit)
+ printf(" %016" PCI_U64_FMT_X "-%016" PCI_U64_FMT_X, base, limit);
+ else
+ printf(" %08x-%08x", (unsigned) base, (unsigned) limit);
}
-
- 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]");
+ printf(" [disabled]");
putchar('\n');
}
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);
+ u32 hw_lower;
+ u32 hw_upper = 0;
+ int broken = 0;
+
if (flg == 0xffffffff)
flg = 0;
if (!pos && !flg && !len)
continue;
+
if (verbose > 1)
printf("\tRegion %d: ", i);
else
putchar('\t');
- 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)))
+
+ /* Read address as seen by the hardware */
+ if (flg & PCI_BASE_ADDRESS_SPACE_IO)
+ hw_lower = flg & PCI_BASE_ADDRESS_IO_MASK;
+ else
+ {
+ hw_lower = flg & PCI_BASE_ADDRESS_MEM_MASK;
+ if ((flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ if (i >= cnt - 1)
+ broken = 1;
+ else
+ {
+ i++;
+ hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ }
+ }
+ }
+
+ /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
+ if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
{
- /* Reported by the OS, but not by the device */
- printf("[virtual] ");
flg = pos;
virtual = 1;
}
+
+ /* Print base address */
if (flg & PCI_BASE_ADDRESS_SPACE_IO)
{
pciaddr_t a = pos & PCI_BASE_ADDRESS_IO_MASK;
printf("I/O ports at ");
if (a || (cmd & PCI_COMMAND_IO))
printf(PCIADDR_PORT_FMT, a);
- else if (flg & PCI_BASE_ADDRESS_IO_MASK)
+ else if (hw_lower)
printf("<ignored>");
else
printf("<unassigned>");
- if (!virtual && !(cmd & PCI_COMMAND_IO))
+ if (virtual)
+ printf(" [virtual]");
+ else if (!(cmd & PCI_COMMAND_IO))
printf(" [disabled]");
}
else
{
int t = flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK;
pciaddr_t a = pos & PCI_ADDR_MEM_MASK;
- int done = 0;
- u32 z = 0;
printf("Memory at ");
- if (t == PCI_BASE_ADDRESS_MEM_TYPE_64)
- {
- if (i >= cnt - 1)
- {
- printf("<invalid-64bit-slot>");
- done = 1;
- }
- else
- {
- i++;
- z = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
- }
- }
- if (!done)
- {
- if (a)
- printf(PCIADDR_T_FMT, a);
- else
- printf(((flg & PCI_BASE_ADDRESS_MEM_MASK) || z) ? "<ignored>" : "<unassigned>");
- }
+ if (broken)
+ printf("<broken-64-bit-slot>");
+ else if (a)
+ printf(PCIADDR_T_FMT, a);
+ else if (hw_lower || hw_upper)
+ printf("<ignored>");
+ else
+ printf("<unassigned>");
printf(" (%s, %sprefetchable)",
(t == PCI_BASE_ADDRESS_MEM_TYPE_32) ? "32-bit" :
(t == PCI_BASE_ADDRESS_MEM_TYPE_64) ? "64-bit" :
(t == PCI_BASE_ADDRESS_MEM_TYPE_1M) ? "low-1M" : "type 3",
(flg & PCI_BASE_ADDRESS_MEM_PREFETCH) ? "" : "non-");
- if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
+ if (virtual)
+ printf(" [virtual]");
+ else if (!(cmd & PCI_COMMAND_MEMORY))
printf(" [disabled]");
}
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ printf(" [enhanced]");
+
show_size(len);
putchar('\n');
}
if (!rom && !flg && !len)
return;
- putchar('\t');
- if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
- printf("[enhanced] ");
- else if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK))
+
+ if ((rom & PCI_ROM_ADDRESS_MASK) && !(flg & PCI_ROM_ADDRESS_MASK) && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
{
- printf("[virtual] ");
flg = rom;
virtual = 1;
}
- printf("Expansion ROM at ");
+
+ printf("\tExpansion ROM at ");
if (rom & PCI_ROM_ADDRESS_MASK)
printf(PCIADDR_T_FMT, rom & PCI_ROM_ADDRESS_MASK);
else if (flg & PCI_ROM_ADDRESS_MASK)
printf("<ignored>");
else
printf("<unassigned>");
+
+ if (virtual)
+ printf(" [virtual]");
+
if (!(flg & PCI_ROM_ADDRESS_ENABLE))
printf(" [disabled]");
else if (!virtual && !(cmd & PCI_COMMAND_MEMORY))
printf(" [disabled by cmd]");
+
+ if (ioflg & PCI_IORESOURCE_PCI_EA_BEI)
+ printf(" [enhanced]");
+
show_size(len);
putchar('\n');
}
byte max_lat, min_gnt;
byte int_pin = get_conf_byte(d, PCI_INTERRUPT_PIN);
unsigned int irq;
- char *dt_node;
+ char *dt_node, *iommu_group;
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);
+ PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
irq = p->irq;
switch (htype)
(int_pin ? 'A' + int_pin - 1 : '?'), irq);
if (p->numa_node != -1)
printf("\tNUMA node: %d\n", p->numa_node);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf("\tIOMMU group: %s\n", iommu_group);
}
else
{
printf(", IRQ " PCIIRQ_FMT, irq);
if (p->numa_node != -1)
printf(", NUMA node %d", p->numa_node);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf(", IOMMU group %s", iommu_group);
putchar('\n');
}
int c;
word sv_id, sd_id;
char classbuf[128], vendbuf[128], devbuf[128], svbuf[128], sdbuf[128];
- char *dt_node;
+ char *dt_node, *iommu_group;
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);
+ pci_fill_info(p, PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP);
printf((opt_machine >= 2) ? "Slot:\t" : "Device:\t");
show_slot_name(d);
putchar('\n');
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);
+ if (iommu_group = pci_get_string_property(p, PCI_FILL_IOMMU_GROUP))
+ printf("IOMMUGroup:\t%s\n", iommu_group);
}
else
{
{
struct device *d;
- if (opt_path)
- grow_tree();
for (d=first_dev; d; d=d->next)
- show_device(d);
+ if (pci_filter_match(&filter, d->dev))
+ show_device(d);
}
/* Main */
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);
pci_init(pacc);
if (opt_map_mode)
{
- if (opt_path)
- die("Bus paths cannot be shown in bus mapping mode");
+ 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();
}