diff options
-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 70f10fa3c1b2..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; |
@@ -250,12 +250,10 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
250 | pci_write_config_dword(dev, pos + 4, 0); | 250 | pci_write_config_dword(dev, pos + 4, 0); |
251 | region.start = 0; | 251 | region.start = 0; |
252 | region.end = sz64; | 252 | region.end = sz64; |
253 | pcibios_bus_to_resource(dev, res, ®ion); | ||
254 | bar_disabled = true; | 253 | bar_disabled = true; |
255 | } else { | 254 | } else { |
256 | region.start = l64; | 255 | region.start = l64; |
257 | region.end = l64 + sz64; | 256 | region.end = l64 + sz64; |
258 | pcibios_bus_to_resource(dev, res, ®ion); | ||
259 | } | 257 | } |
260 | } else { | 258 | } else { |
261 | sz = pci_size(l, sz, mask); | 259 | sz = pci_size(l, sz, mask); |
@@ -265,7 +263,28 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
265 | 263 | ||
266 | region.start = l; | 264 | region.start = l; |
267 | region.end = l + sz; | 265 | region.end = l + sz; |
268 | pcibios_bus_to_resource(dev, res, ®ion); | 266 | } |
267 | |||
268 | pcibios_bus_to_resource(dev, res, ®ion); | ||
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, ®ion.start); | ||
285 | res->flags |= IORESOURCE_UNSET; | ||
286 | res->end -= res->start; | ||
287 | res->start = 0; | ||
269 | } | 288 | } |
270 | 289 | ||
271 | goto out; | 290 | goto out; |
@@ -278,9 +297,9 @@ out: | |||
278 | pci_write_config_word(dev, PCI_COMMAND, orig_cmd); | 297 | pci_write_config_word(dev, PCI_COMMAND, orig_cmd); |
279 | 298 | ||
280 | if (bar_too_big) | 299 | if (bar_too_big) |
281 | dev_err(&dev->dev, "reg %x: can't handle 64-bit BAR\n", pos); | 300 | dev_err(&dev->dev, "reg 0x%x: can't handle 64-bit BAR\n", pos); |
282 | if (res->flags && !bar_disabled) | 301 | if (res->flags && !bar_disabled) |
283 | dev_printk(KERN_DEBUG, &dev->dev, "reg %x: %pR\n", pos, res); | 302 | dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); |
284 | 303 | ||
285 | return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; | 304 | return (res->flags & IORESOURCE_MEM_64) ? 1 : 0; |
286 | } | 305 | } |