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 | } |
