aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorBjorn Helgaas <bhelgaas@google.com>2012-06-19 09:45:44 -0400
committerBjorn Helgaas <bhelgaas@google.com>2012-06-20 19:28:53 -0400
commit8f38eaca55d0fab7499b33adb1dec33e16de5abb (patch)
treed5f7a0b123d073b8fb75ca46e82e1862f88a9e13 /drivers/pci
parent8291550f8479fde2cee571d1b367e6918819f189 (diff)
PCI: fix P2P bridge I/O port window sign extension
On P2P bridges with 32-bit I/O decoding, we incorrectly sign-extended windows starting at 0x80000000 or above. In "base |= (io_base_hi << 16)", "io_base_hi" is promoted to a signed int before being extended to an unsigned long. This would cause a window starting at I/O address 0x80000000 to be treated as though it started at 0xffffffff80008000 instead, which should cause "no compatible bridge window" errors when we enumerate devices using that I/O space. The mmio and mmio_pref casts are not strictly necessary, but without them, correctness depends on the types of the PCI_MEMORY_RANGE_MASK and PCI_PREF_RANGE_MASK constants, which are not obvious from reading the local code. Found by Coverity (CID 138747 and CID 138748). Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/probe.c18
1 files changed, 10 insertions, 8 deletions
diff --git a/drivers/pci/probe.c b/drivers/pci/probe.c
index 658ac977cb56..a7a504fc82b9 100644
--- a/drivers/pci/probe.c
+++ b/drivers/pci/probe.c
@@ -281,10 +281,11 @@ static void __devinit pci_read_bridge_io(struct pci_bus *child)
281 281
282 if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) { 282 if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
283 u16 io_base_hi, io_limit_hi; 283 u16 io_base_hi, io_limit_hi;
284
284 pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi); 285 pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
285 pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi); 286 pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
286 base |= (io_base_hi << 16); 287 base |= ((unsigned long) io_base_hi << 16);
287 limit |= (io_limit_hi << 16); 288 limit |= ((unsigned long) io_limit_hi << 16);
288 } 289 }
289 290
290 if (base && base <= limit) { 291 if (base && base <= limit) {
@@ -312,8 +313,8 @@ static void __devinit pci_read_bridge_mmio(struct pci_bus *child)
312 res = child->resource[1]; 313 res = child->resource[1];
313 pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); 314 pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
314 pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo); 315 pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
315 base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16; 316 base = ((unsigned long) mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
316 limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16; 317 limit = ((unsigned long) mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
317 if (base && base <= limit) { 318 if (base && base <= limit) {
318 res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM; 319 res->flags = (mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | IORESOURCE_MEM;
319 region.start = base; 320 region.start = base;
@@ -334,11 +335,12 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
334 res = child->resource[2]; 335 res = child->resource[2];
335 pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); 336 pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
336 pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo); 337 pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
337 base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16; 338 base = ((unsigned long) mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
338 limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16; 339 limit = ((unsigned long) mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
339 340
340 if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) { 341 if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
341 u32 mem_base_hi, mem_limit_hi; 342 u32 mem_base_hi, mem_limit_hi;
343
342 pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi); 344 pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
343 pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi); 345 pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
344 346
@@ -349,8 +351,8 @@ static void __devinit pci_read_bridge_mmio_pref(struct pci_bus *child)
349 */ 351 */
350 if (mem_base_hi <= mem_limit_hi) { 352 if (mem_base_hi <= mem_limit_hi) {
351#if BITS_PER_LONG == 64 353#if BITS_PER_LONG == 64
352 base |= ((long) mem_base_hi) << 32; 354 base |= ((unsigned long) mem_base_hi) << 32;
353 limit |= ((long) mem_limit_hi) << 32; 355 limit |= ((unsigned long) mem_limit_hi) << 32;
354#else 356#else
355 if (mem_base_hi || mem_limit_hi) { 357 if (mem_base_hi || mem_limit_hi) {
356 dev_err(&dev->dev, "can't handle 64-bit " 358 dev_err(&dev->dev, "can't handle 64-bit "