diff options
Diffstat (limited to 'drivers/pci/probe.c')
-rw-r--r-- | drivers/pci/probe.c | 80 |
1 files changed, 35 insertions, 45 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c index 5ed99309c758..a9e34ca119e1 100644 --- a/drivers/pci/probe.c +++ b/drivers/pci/probe.c | |||
@@ -87,8 +87,7 @@ static void release_pcibus_dev(struct device *dev) | |||
87 | { | 87 | { |
88 | struct pci_bus *pci_bus = to_pci_bus(dev); | 88 | struct pci_bus *pci_bus = to_pci_bus(dev); |
89 | 89 | ||
90 | if (pci_bus->bridge) | 90 | put_device(pci_bus->bridge); |
91 | put_device(pci_bus->bridge); | ||
92 | pci_bus_remove_resources(pci_bus); | 91 | pci_bus_remove_resources(pci_bus); |
93 | pci_release_bus_of_node(pci_bus); | 92 | pci_release_bus_of_node(pci_bus); |
94 | kfree(pci_bus); | 93 | kfree(pci_bus); |
@@ -175,7 +174,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
175 | u64 l64, sz64, mask64; | 174 | u64 l64, sz64, mask64; |
176 | u16 orig_cmd; | 175 | u16 orig_cmd; |
177 | struct pci_bus_region region, inverted_region; | 176 | struct pci_bus_region region, inverted_region; |
178 | bool bar_too_big = false, bar_too_high = false, bar_invalid = false; | ||
179 | 177 | ||
180 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; | 178 | mask = type ? PCI_ROM_ADDRESS_MASK : ~0; |
181 | 179 | ||
@@ -201,8 +199,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
201 | * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit | 199 | * memory BAR or a ROM, bit 0 must be clear; if it's an io BAR, bit |
202 | * 1 must be clear. | 200 | * 1 must be clear. |
203 | */ | 201 | */ |
204 | if (!sz || sz == 0xffffffff) | 202 | if (sz == 0xffffffff) |
205 | goto fail; | 203 | sz = 0; |
206 | 204 | ||
207 | /* | 205 | /* |
208 | * I don't know how l can have all bits set. Copied from old code. | 206 | * I don't know how l can have all bits set. Copied from old code. |
@@ -215,23 +213,22 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
215 | res->flags = decode_bar(dev, l); | 213 | res->flags = decode_bar(dev, l); |
216 | res->flags |= IORESOURCE_SIZEALIGN; | 214 | res->flags |= IORESOURCE_SIZEALIGN; |
217 | if (res->flags & IORESOURCE_IO) { | 215 | if (res->flags & IORESOURCE_IO) { |
218 | l &= PCI_BASE_ADDRESS_IO_MASK; | 216 | l64 = l & PCI_BASE_ADDRESS_IO_MASK; |
219 | mask = PCI_BASE_ADDRESS_IO_MASK & (u32) IO_SPACE_LIMIT; | 217 | sz64 = sz & PCI_BASE_ADDRESS_IO_MASK; |
218 | mask64 = PCI_BASE_ADDRESS_IO_MASK & (u32)IO_SPACE_LIMIT; | ||
220 | } else { | 219 | } else { |
221 | l &= PCI_BASE_ADDRESS_MEM_MASK; | 220 | l64 = l & PCI_BASE_ADDRESS_MEM_MASK; |
222 | mask = (u32)PCI_BASE_ADDRESS_MEM_MASK; | 221 | sz64 = sz & PCI_BASE_ADDRESS_MEM_MASK; |
222 | mask64 = (u32)PCI_BASE_ADDRESS_MEM_MASK; | ||
223 | } | 223 | } |
224 | } else { | 224 | } else { |
225 | res->flags |= (l & IORESOURCE_ROM_ENABLE); | 225 | res->flags |= (l & IORESOURCE_ROM_ENABLE); |
226 | l &= PCI_ROM_ADDRESS_MASK; | 226 | l64 = l & PCI_ROM_ADDRESS_MASK; |
227 | mask = (u32)PCI_ROM_ADDRESS_MASK; | 227 | sz64 = sz & PCI_ROM_ADDRESS_MASK; |
228 | mask64 = (u32)PCI_ROM_ADDRESS_MASK; | ||
228 | } | 229 | } |
229 | 230 | ||
230 | if (res->flags & IORESOURCE_MEM_64) { | 231 | if (res->flags & IORESOURCE_MEM_64) { |
231 | l64 = l; | ||
232 | sz64 = sz; | ||
233 | mask64 = mask | (u64)~0 << 32; | ||
234 | |||
235 | pci_read_config_dword(dev, pos + 4, &l); | 232 | pci_read_config_dword(dev, pos + 4, &l); |
236 | pci_write_config_dword(dev, pos + 4, ~0); | 233 | pci_write_config_dword(dev, pos + 4, ~0); |
237 | pci_read_config_dword(dev, pos + 4, &sz); | 234 | pci_read_config_dword(dev, pos + 4, &sz); |
@@ -239,18 +236,30 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
239 | 236 | ||
240 | l64 |= ((u64)l << 32); | 237 | l64 |= ((u64)l << 32); |
241 | sz64 |= ((u64)sz << 32); | 238 | sz64 |= ((u64)sz << 32); |
239 | mask64 |= ((u64)~0 << 32); | ||
240 | } | ||
242 | 241 | ||
243 | sz64 = pci_size(l64, sz64, mask64); | 242 | if (!dev->mmio_always_on && (orig_cmd & PCI_COMMAND_DECODE_ENABLE)) |
243 | pci_write_config_word(dev, PCI_COMMAND, orig_cmd); | ||
244 | 244 | ||
245 | if (!sz64) | 245 | if (!sz64) |
246 | goto fail; | 246 | goto fail; |
247 | 247 | ||
248 | sz64 = pci_size(l64, sz64, mask64); | ||
249 | if (!sz64) { | ||
250 | dev_info(&dev->dev, FW_BUG "reg 0x%x: invalid BAR (can't size)\n", | ||
251 | pos); | ||
252 | goto fail; | ||
253 | } | ||
254 | |||
255 | if (res->flags & IORESOURCE_MEM_64) { | ||
248 | if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && | 256 | if ((sizeof(dma_addr_t) < 8 || sizeof(resource_size_t) < 8) && |
249 | sz64 > 0x100000000ULL) { | 257 | sz64 > 0x100000000ULL) { |
250 | res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; | 258 | res->flags |= IORESOURCE_UNSET | IORESOURCE_DISABLED; |
251 | res->start = 0; | 259 | res->start = 0; |
252 | res->end = 0; | 260 | res->end = 0; |
253 | bar_too_big = true; | 261 | dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", |
262 | pos, (unsigned long long)sz64); | ||
254 | goto out; | 263 | goto out; |
255 | } | 264 | } |
256 | 265 | ||
@@ -259,22 +268,15 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
259 | res->flags |= IORESOURCE_UNSET; | 268 | res->flags |= IORESOURCE_UNSET; |
260 | res->start = 0; | 269 | res->start = 0; |
261 | res->end = sz64; | 270 | res->end = sz64; |
262 | bar_too_high = true; | 271 | dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4GB (bus address %#010llx)\n", |
272 | pos, (unsigned long long)l64); | ||
263 | goto out; | 273 | goto out; |
264 | } else { | ||
265 | region.start = l64; | ||
266 | region.end = l64 + sz64; | ||
267 | } | 274 | } |
268 | } else { | ||
269 | sz = pci_size(l, sz, mask); | ||
270 | |||
271 | if (!sz) | ||
272 | goto fail; | ||
273 | |||
274 | region.start = l; | ||
275 | region.end = l + sz; | ||
276 | } | 275 | } |
277 | 276 | ||
277 | region.start = l64; | ||
278 | region.end = l64 + sz64; | ||
279 | |||
278 | pcibios_bus_to_resource(dev->bus, res, ®ion); | 280 | pcibios_bus_to_resource(dev->bus, res, ®ion); |
279 | pcibios_resource_to_bus(dev->bus, &inverted_region, res); | 281 | pcibios_resource_to_bus(dev->bus, &inverted_region, res); |
280 | 282 | ||
@@ -293,7 +295,8 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
293 | res->flags |= IORESOURCE_UNSET; | 295 | res->flags |= IORESOURCE_UNSET; |
294 | res->start = 0; | 296 | res->start = 0; |
295 | res->end = region.end - region.start; | 297 | res->end = region.end - region.start; |
296 | bar_invalid = true; | 298 | dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", |
299 | pos, (unsigned long long)region.start); | ||
297 | } | 300 | } |
298 | 301 | ||
299 | goto out; | 302 | goto out; |
@@ -302,19 +305,6 @@ int __pci_read_base(struct pci_dev *dev, enum pci_bar_type type, | |||
302 | fail: | 305 | fail: |
303 | res->flags = 0; | 306 | res->flags = 0; |
304 | out: | 307 | out: |
305 | if (!dev->mmio_always_on && | ||
306 | (orig_cmd & PCI_COMMAND_DECODE_ENABLE)) | ||
307 | pci_write_config_word(dev, PCI_COMMAND, orig_cmd); | ||
308 | |||
309 | if (bar_too_big) | ||
310 | dev_err(&dev->dev, "reg 0x%x: can't handle BAR larger than 4GB (size %#010llx)\n", | ||
311 | pos, (unsigned long long) sz64); | ||
312 | if (bar_too_high) | ||
313 | dev_info(&dev->dev, "reg 0x%x: can't handle BAR above 4G (bus address %#010llx)\n", | ||
314 | pos, (unsigned long long) l64); | ||
315 | if (bar_invalid) | ||
316 | dev_info(&dev->dev, "reg 0x%x: initial BAR value %#010llx invalid\n", | ||
317 | pos, (unsigned long long) region.start); | ||
318 | if (res->flags) | 308 | if (res->flags) |
319 | dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); | 309 | dev_printk(KERN_DEBUG, &dev->dev, "reg 0x%x: %pR\n", pos, res); |
320 | 310 | ||