From 7f96c3feb701dea64c1941d27ef590cd03781b55 Mon Sep 17 00:00:00 2001 From: =?utf8?q?Pali=20Roh=C3=A1r?= Date: Sun, 6 Mar 2022 00:22:03 +0100 Subject: [PATCH] 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. --- lspci.c | 40 +++++++++++++++++----------------------- 1 file 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; ibase_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) { -- 2.39.2