aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPali Rohár <pali@kernel.org>2022-03-06 00:22:03 +0100
committerPali Rohár <pali@kernel.org>2022-04-16 00:01:13 +0200
commit7f96c3feb701dea64c1941d27ef590cd03781b55 (patch)
tree7ee5b24ba49f94c3d31be16b9cd9ce06ca0c5455
parent7eb8b9473317562e0b66bd3e8c467e127d88dac8 (diff)
downloadpciutils-7f96c3feb701dea64c1941d27ef590cd03781b55.tar.gz
lspci: Fix detection of virtual regions
There are many issues with detection of virtual regions. 1. Variable for detecting virtual region is global and if one BAR is marked as virtual then all remaining BARs are treated as virtual too as this variable is not reset at next loop iteration. 2. Lower address is read from flg variable which on backends without config space is initialized from PCI flags, not from base address. 3. Code mixes at many places PCI flags, resource flags, PCI addresses and resource addresses. Some backends reports PCI flags in PCI addresses, some not. Cleanup mess of ->base_addr, ->flags and PCI_BASE_ADDRESS. If backend provides ->flags value (test via PCI_FILL_IO_FLAGS) then use it instead of reading flags from pci config space. Fix reading of PCI hw_lower and hw_upper addresses. If PCI_BASE_ADDRESS reports different type than what is stored in base_addr then completely ignore hw_lower and hw_upper values. It means that backend either provide fiction information or provide resources in different order as they are stored in hardware. In any case values from HW cannot be used as they do not match values reported by backend. And in the last case, make virtual variable local to the current BAR processing and do not increment loop variable i when 64-bit MEM type is detected via data from config space. It could miss some virtual resource reported by the backend. This change fixes displaying resources of PCI devices which have some unset/unused BARs in the middle and OS reports virtual regions and remaining regions without holes. E.g. HW BARs 0, 2, 5 are used and OS reports base_addr 0, 1, 2, 3.
-rw-r--r--lspci.c40
1 files changed, 17 insertions, 23 deletions
diff --git a/lspci.c b/lspci.c
index ed8c864..b16f585 100644
--- a/lspci.c
+++ b/lspci.c
@@ -397,17 +397,17 @@ show_bases(struct device *d, int cnt, int without_config_data)
struct pci_dev *p = d->dev;
word cmd = without_config_data ? (PCI_COMMAND_IO | PCI_COMMAND_MEMORY) : get_conf_word(d, PCI_COMMAND);
int i;
- int virtual = 0;
for (i=0; i<cnt; i++)
{
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 = without_config_data ? ioflg_to_pciflg(ioflg) : get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
- u32 hw_lower;
+ u32 flg = (p->known_fields & PCI_FILL_IO_FLAGS) ? ioflg_to_pciflg(ioflg) : without_config_data ? 0 : get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ u32 hw_lower = 0;
u32 hw_upper = 0;
int broken = 0;
+ int virtual = 0;
if (flg == 0xffffffff)
flg = 0;
@@ -419,32 +419,26 @@ show_bases(struct device *d, int cnt, int without_config_data)
else
putchar('\t');
- /* Read address as seen by the hardware */
- if (flg & PCI_BASE_ADDRESS_SPACE_IO)
- hw_lower = flg & PCI_BASE_ADDRESS_IO_MASK;
- else
+ /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
+ if ((p->known_fields & PCI_FILL_IO_FLAGS) && !without_config_data)
{
- hw_lower = flg & PCI_BASE_ADDRESS_MEM_MASK;
- if ((flg & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ /* Read address as seen by the hardware */
+ hw_lower = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ if ((hw_lower & PCI_BASE_ADDRESS_SPACE) == (ioflg_to_pciflg(ioflg) & PCI_BASE_ADDRESS_SPACE))
{
- if (i >= cnt - 1)
- broken = 1;
- else
- {
- i++;
- if (!without_config_data)
- hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i);
+ if ((ioflg & PCI_IORESOURCE_TYPE_BITS) == PCI_IORESOURCE_MEM &&
+ (hw_lower & PCI_BASE_ADDRESS_MEM_TYPE_MASK) == PCI_BASE_ADDRESS_MEM_TYPE_64)
+ {
+ if (i >= cnt - 1)
+ broken = 1;
+ else
+ hw_upper = get_conf_long(d, PCI_BASE_ADDRESS_0 + 4*i + 1);
}
+ if (pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
+ virtual = 1;
}
}
- /* Detect virtual regions, which are reported by the OS, but unassigned in the device */
- if (!without_config_data && pos && !hw_lower && !hw_upper && !(ioflg & PCI_IORESOURCE_PCI_EA_BEI))
- {
- flg = pos;
- virtual = 1;
- }
-
/* Print base address */
if (flg & PCI_BASE_ADDRESS_SPACE_IO)
{