aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/probe.c
diff options
context:
space:
mode:
authorKevin Hao <haokexin@gmail.com>2013-05-25 07:36:27 -0400
committerBjorn Helgaas <bhelgaas@google.com>2013-05-25 14:02:56 -0400
commitcf4d1cf5ac5e7d2b886af6ed906ea0dcdc5b6855 (patch)
tree81a359610daf421855e183077baa86f3d4d99f9c /drivers/pci/probe.c
parent96ddef25b24a6159e78fb53c1b13336914ff1154 (diff)
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>
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r--drivers/pci/probe.c22
1 files changed, 21 insertions, 1 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index cd7b6de9376c..fe5b50bd7536 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,
170{ 170{
171 u32 l, sz, mask; 171 u32 l, sz, mask;
172 u16 orig_cmd; 172 u16 orig_cmd;
173 struct pci_bus_region region; 173 struct pci_bus_region region, inverted_region;
174 bool bar_too_big = false, bar_disabled = false; 174 bool bar_too_big = false, bar_disabled = false;
175 175
176 mask = type ? PCI_ROM_ADDRESS_MASK : ~0; 176 mask = type ? PCI_ROM_ADDRESS_MASK : ~0;
@@ -266,6 +266,26 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type,
266 } 266 }
267 267
268 pcibios_bus_to_resource(dev, res, &region); 268 pcibios_bus_to_resource(dev, res, &region);
269 pcibios_resource_to_bus(dev, &inverted_region, res);
270
271 /*
272 * If "A" is a BAR value (a bus address), "bus_to_resource(A)" is
273 * the corresponding resource address (the physical address used by
274 * the CPU. Converting that resource address back to a bus address
275 * should yield the original BAR value:
276 *
277 * resource_to_bus(bus_to_resource(A)) == A
278 *
279 * If it doesn't, CPU accesses to "bus_to_resource(A)" will not
280 * be claimed by the device.
281 */
282 if (inverted_region.start != region.start) {
283 dev_info(&dev->dev, "reg 0x%x: initial BAR value %pa invalid; forcing reassignment\n",
284 pos, &region.start);
285 res->flags |= IORESOURCE_UNSET;
286 res->end -= res->start;
287 res->start = 0;
288 }
269 289
270 goto out; 290 goto out;
271 291