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