PCI: Unset resource if initial BAR value is invalid
The initial BAR value in the following example is invalid: pci_bus 0000:00: root bus resource [mem 0xa0000000-0xbfffffff] (bus address [0xe0000000-0xffffffff]) pci 0000:01:00.0: reg 10: initial BAR value: 0xa0000000 pci 0000:01:00.0: reg 10: [mem 0xa0000000-0xa000007f 64bit] bus_to_resource(0xa0000000) yields 0xa0000000 because there's no host bridge window whose bus address range contains 0xa0000000. But CPU accesses to 0xa0000000 appear on the bus at 0xe0000000, so they will not be claimed if the BAR contains 0xa0000000. If we find a BAR where resource_to_bus(bus_to_resource(A)) != A, we can work around this problem by reassigning the BAR. [bhelgaas: changelog, comment] Reference: https://lkml.kernel.org/r/1368536876-27307-3-git-send-email-haokexin@gmail.com Signed-off-by: Kevin Hao <haokexin@gmail.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
This commit is contained in:
parent
96ddef25b2
commit
cf4d1cf5ac
|
@ -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;
|
||||
|
@ -266,6 +266,26 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
|
|||
}
|
||||
|
||||
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;
|
||||
|
||||
|
|
Loading…
Reference in a new issue