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