aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2021-11-20 15:13:20 +0100
committerMartin Mares <mj@ucw.cz>2022-02-10 13:49:35 +0100
commitccf68033a452cd32ac4c1f7d8618e79102bd08a8 (patch)
tree71bcfa224de86cb878f76e76548506dfd3304285
parent119c1376f9ca4d359a1816af9d31f4a2c2c83307 (diff)
downloadpciutils-ccf68033a452cd32ac4c1f7d8618e79102bd08a8.tar.gz
lspci: Use PCI_FILL_BRIDGE_BASES to detect if range behind bridge is disabled or unsupported
Show resources behind bridge as reported by PCI_FILL_BRIDGE_BASES. I/O or Prefetchable memory behind bridge is unsupported by bridge if both base and limit bridge registers are read-only and returns zero. So if base and limit registers returns zero (which is valid enabled range) and kernel reports that particular resource is disabled it means that resource is unsupported. Both I/O or Prefetchable memory resources are only optional.
-rw-r--r--lspci.c58
1 files changed, 49 insertions, 9 deletions
diff --git a/lspci.c b/lspci.c
index 67ac19b..d14d1b9 100644
--- a/lspci.c
+++ b/lspci.c
@@ -374,12 +374,12 @@ show_size(u64 x)
}
static void
-show_range(char *prefix, u64 base, u64 limit, int bits)
+show_range(char *prefix, u64 base, u64 limit, int bits, int disabled)
{
printf("%s:", prefix);
if (base <= limit || verbose > 2)
printf(" %0*" PCI_U64_FMT_X "-%0*" PCI_U64_FMT_X, (bits+3)/4, base, (bits+3)/4, limit);
- if (base <= limit)
+ if (!disabled && base <= limit)
show_size(limit - base + 1);
else
printf(" [disabled]");
@@ -543,6 +543,7 @@ show_htype0(struct device *d)
static void
show_htype1(struct device *d)
{
+ struct pci_dev *p = d->dev;
u32 io_base = get_conf_byte(d, PCI_IO_BASE);
u32 io_limit = get_conf_byte(d, PCI_IO_LIMIT);
u32 io_type = io_base & PCI_IO_RANGE_TYPE_MASK;
@@ -554,6 +555,10 @@ 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 io_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[0];
+ int mem_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[1];
+ int pref_disabled = (p->known_fields & PCI_FILL_BRIDGE_BASES) && !p->bridge_size[2];
+ int io_bits, pref_bits;
show_bases(d, 2);
printf("\tBus: primary=%02x, secondary=%02x, subordinate=%02x, sec-latency=%d\n",
@@ -562,7 +567,15 @@ show_htype1(struct device *d)
get_conf_byte(d, PCI_SUBORDINATE_BUS),
get_conf_byte(d, PCI_SEC_LATENCY_TIMER));
- if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
+ if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !io_disabled)
+ {
+ io_base = p->bridge_base_addr[0] & PCI_IO_RANGE_MASK;
+ io_limit = io_base + p->bridge_size[0] - 1;
+ io_type = p->bridge_base_addr[0] & PCI_IO_RANGE_TYPE_MASK;
+ io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
+ show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
+ }
+ else if (io_type != (io_limit & PCI_IO_RANGE_TYPE_MASK) ||
(io_type != PCI_IO_RANGE_TYPE_16 && io_type != PCI_IO_RANGE_TYPE_32))
printf("\t!!! Unknown I/O range types %x/%x\n", io_base, io_limit);
else
@@ -574,20 +587,40 @@ 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);
}
- show_range("\tI/O behind bridge", io_base, io_limit+0xfff, (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16);
+ /* I/O is unsupported if both base and limit are zeros and resource is disabled */
+ if (!(io_base == 0x0 && io_limit == 0x0 && io_disabled))
+ {
+ io_limit += 0xfff;
+ io_bits = (io_type == PCI_IO_RANGE_TYPE_32) ? 32 : 16;
+ show_range("\tI/O behind bridge", io_base, io_limit, io_bits, io_disabled);
+ }
}
- if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
+ if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !mem_disabled)
+ {
+ mem_base = p->bridge_base_addr[1] & PCI_MEMORY_RANGE_MASK;
+ mem_limit = mem_base + p->bridge_size[1] - 1;
+ show_range("\tMemory behind bridge", mem_base, mem_limit, 32, mem_disabled);
+ }
+ else if (mem_type != (mem_limit & PCI_MEMORY_RANGE_TYPE_MASK) ||
mem_type)
printf("\t!!! Unknown memory range types %x/%x\n", mem_base, mem_limit);
else
{
mem_base = (mem_base & PCI_MEMORY_RANGE_MASK) << 16;
mem_limit = (mem_limit & PCI_MEMORY_RANGE_MASK) << 16;
- show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 32);
+ show_range("\tMemory behind bridge", mem_base, mem_limit + 0xfffff, 32, mem_disabled);
}
- if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
+ if ((p->known_fields & PCI_FILL_BRIDGE_BASES) && !pref_disabled)
+ {
+ u64 pref_base_64 = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_MASK;
+ u64 pref_limit_64 = pref_base_64 + p->bridge_size[2] - 1;
+ pref_type = p->bridge_base_addr[2] & PCI_MEMORY_RANGE_TYPE_MASK;
+ pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
+ show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
+ }
+ else if (pref_type != (pref_limit & PCI_PREF_RANGE_TYPE_MASK) ||
(pref_type != PCI_PREF_RANGE_TYPE_32 && pref_type != PCI_PREF_RANGE_TYPE_64))
printf("\t!!! Unknown prefetchable memory range types %x/%x\n", pref_base, pref_limit);
else
@@ -599,7 +632,13 @@ show_htype1(struct device *d)
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) ? 64 : 32);
+ /* Prefetchable memory is unsupported if both base and limit are zeros and resource is disabled */
+ if (!(pref_base_64 == 0x0 && pref_limit_64 == 0x0 && pref_disabled))
+ {
+ pref_limit_64 += 0xfffff;
+ pref_bits = (pref_type == PCI_PREF_RANGE_TYPE_64) ? 64 : 32;
+ show_range("\tPrefetchable memory behind bridge", pref_base_64, pref_limit_64, pref_bits, pref_disabled);
+ }
}
if (verbose > 1)
@@ -726,7 +765,8 @@ show_verbose(struct device *d)
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_IOMMU_GROUP);
+ PCI_FILL_PHYS_SLOT | PCI_FILL_NUMA_NODE | PCI_FILL_DT_NODE | PCI_FILL_IOMMU_GROUP |
+ PCI_FILL_BRIDGE_BASES);
irq = p->irq;
switch (htype)