diff options
Diffstat (limited to 'drivers')
-rw-r--r-- | drivers/pci/probe.c | 31 |
1 files changed, 25 insertions, 6 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 70f10fa..fe5b50b 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c @@ -170,7 +170,7 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, { u32 l, sz, mask; u16 orig_cmd; - struct pci_bus_region region; + struct pci_bus_region region, inverted_region; bool bar_too_big = false, bar_disabled = false; mask = type ? PCI_ROM_ADDRESS_MASK : ~0; @@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, pci_write_config_dword(dev, pos + 4, 0); region.start = 0; region.end = sz64; - pcibios_bus_to_resource(dev, res, ®ion); bar_disabled = true; } else { region.start = l64; region.end = l64 + sz64; - pcibios_bus_to_resource(dev, res, ®ion); } } else { sz = pci_size(l, sz, mask); @@ -265,7 +263,28 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, region.start = l; region.end = l + sz; - pcibios_bus_to_resource(dev, res, ®ion); + } + + pcibios_bus_to_resource(dev, res, ®ion); + pcibios_resource_to_bus(dev, &inverted_region, res); + + /* + * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is + * the corresponding resource address (the physical address used by + * the CPU. Converting that resource address back to a bus address + * should yield the original BAR value: + * + * resource_to_bus(bus_to_resource(A)) == A + * + * If it doesn't, CPU accesses to "bus_to_resource(A)" will not + * be claimed by the device. + */ + if (inverted_region.start != region.start) { + dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n", + pos, ®ion.start); + res->flags |= IORESOURCE_UNSET; + res->end -= res->start; + res->start = 0; } goto out; @@ -278,9 +297,9 @@ out: pci_write_config_word(dev, PCI_COMMAND, orig_cmd); if (bar_too_big) - dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); + dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); if (res->flags && !bar_disabled) - dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); + dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; } |