diff options
author | Pali Rohár <pali@kernel.org> | 2022-03-06 00:22:03 +0100 |
---|---|---|
committer | Pali Rohár <pali@kernel.org> | 2022-04-16 00:01:13 +0200 |
commit | 7f96c3feb701dea64c1941d27ef590cd03781b55 (patch) | |
tree | 7ee5b24ba49f94c3d31be16b9cd9ce06ca0c5455 | |
parent | 7eb8b9473317562e0b66bd3e8c467e127d88dac8 (diff) | |
download | pciutils-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.c | 40 |
1 files changed, 17 insertions, 23 deletions
@@ -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) { |