diff options
author | Bjorn Helgaas <bhelgaas@google.com> | 2012-03-16 19:48:24 -0400 |
---|---|---|
committer | Jesse Barnes <jbarnes@virtuousgeek.org> | 2012-03-20 13:42:01 -0400 |
commit | a031589bc04086250d0a4d89dd277a70d74ed8fa (patch) | |
tree | 8e5be9945ffc950952d86b970c92af8738a9fe45 /arch/sparc/kernel | |
parent | c0f209468e8b6c81b28f6417e7d88c99171d20b6 (diff) |
sparc/PCI: convert devtree and arch-probed bus addresses to resource
Normal PCI enumeration via PCI config space uses __pci_read_base(), where
the PCI core applies any bus-to-resource offset. But sparc sometimes
reads PCI config space itself, and sometimes it gets addresses from the
device tree.
In ac1edcc579b6, I converted sparc to use the PCI core bus-to-resource
conversion, but I missed these sparc-specific paths. I don't have a way
to test it, but I think sparc is broken between that commit and this one.
This patch replaces the sparc-specific pci_resource_adjust() with the
generic pcibios_bus_to_resource() in the following paths:
pci_cfg_fake_ranges() (addresses read from PCI config)
apb_fake_ranges() (addresses computed based on PCI config)
of_scan_pci_bridge() (addresses from OF "ranges" property)
N.B.: Resources of non-P2P bridge devices are set in pci_parse_of_addrs()
and, as far as I can see, never converted to CPU addresses. I do not
understand why these would be treated differently than bridge windows.
CC: "David S. Miller" <davem@davemloft.net>
CC: sparclinux@vger.kernel.org
Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
Diffstat (limited to 'arch/sparc/kernel')
-rw-r--r-- | arch/sparc/kernel/pci.c | 60 |
1 files changed, 25 insertions, 35 deletions
diff --git a/arch/sparc/kernel/pci.c b/arch/sparc/kernel/pci.c index 253e8ac2783f..fdaf21811670 100644 --- a/arch/sparc/kernel/pci.c +++ b/arch/sparc/kernel/pci.c | |||
@@ -375,13 +375,6 @@ static void __devinit apb_calc_first_last(u8 map, u32 *first_p, u32 *last_p) | |||
375 | *last_p = last; | 375 | *last_p = last; |
376 | } | 376 | } |
377 | 377 | ||
378 | static void pci_resource_adjust(struct resource *res, | ||
379 | struct resource *root) | ||
380 | { | ||
381 | res->start += root->start; | ||
382 | res->end += root->start; | ||
383 | } | ||
384 | |||
385 | /* For PCI bus devices which lack a 'ranges' property we interrogate | 378 | /* For PCI bus devices which lack a 'ranges' property we interrogate |
386 | * the config space values to set the resources, just like the generic | 379 | * the config space values to set the resources, just like the generic |
387 | * Linux PCI probing code does. | 380 | * Linux PCI probing code does. |
@@ -390,7 +383,8 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, | |||
390 | struct pci_bus *bus, | 383 | struct pci_bus *bus, |
391 | struct pci_pbm_info *pbm) | 384 | struct pci_pbm_info *pbm) |
392 | { | 385 | { |
393 | struct resource *res; | 386 | struct pci_bus_region region; |
387 | struct resource *res, res2; | ||
394 | u8 io_base_lo, io_limit_lo; | 388 | u8 io_base_lo, io_limit_lo; |
395 | u16 mem_base_lo, mem_limit_lo; | 389 | u16 mem_base_lo, mem_limit_lo; |
396 | unsigned long base, limit; | 390 | unsigned long base, limit; |
@@ -412,11 +406,14 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, | |||
412 | res = bus->resource[0]; | 406 | res = bus->resource[0]; |
413 | if (base <= limit) { | 407 | if (base <= limit) { |
414 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; | 408 | res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO; |
409 | res2.flags = res->flags; | ||
410 | region.start = base; | ||
411 | region.end = limit + 0xfff; | ||
412 | pcibios_bus_to_resource(dev, &res2, ®ion); | ||
415 | if (!res->start) | 413 | if (!res->start) |
416 | res->start = base; | 414 | res->start = res2.start; |
417 | if (!res->end) | 415 | if (!res->end) |
418 | res->end = limit + 0xfff; | 416 | res->end = res2.end; |
419 | pci_resource_adjust(res, &pbm->io_space); | ||
420 | } | 417 | } |
421 | 418 | ||
422 | pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); | 419 | pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo); |
@@ -428,9 +425,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, | |||
428 | if (base <= limit) { | 425 | if (base <= limit) { |
429 | res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | | 426 | res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | |
430 | IORESOURCE_MEM); | 427 | IORESOURCE_MEM); |
431 | res->start = base; | 428 | region.start = base; |
432 | res->end = limit + 0xfffff; | 429 | region.end = limit + 0xfffff; |
433 | pci_resource_adjust(res, &pbm->mem_space); | 430 | pcibios_bus_to_resource(dev, res, ®ion); |
434 | } | 431 | } |
435 | 432 | ||
436 | pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); | 433 | pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo); |
@@ -459,9 +456,9 @@ static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev, | |||
459 | if (base <= limit) { | 456 | if (base <= limit) { |
460 | res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | | 457 | res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) | |
461 | IORESOURCE_MEM | IORESOURCE_PREFETCH); | 458 | IORESOURCE_MEM | IORESOURCE_PREFETCH); |
462 | res->start = base; | 459 | region.start = base; |
463 | res->end = limit + 0xfffff; | 460 | region.end = limit + 0xfffff; |
464 | pci_resource_adjust(res, &pbm->mem_space); | 461 | pcibios_bus_to_resource(dev, res, ®ion); |
465 | } | 462 | } |
466 | } | 463 | } |
467 | 464 | ||
@@ -472,6 +469,7 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev, | |||
472 | struct pci_bus *bus, | 469 | struct pci_bus *bus, |
473 | struct pci_pbm_info *pbm) | 470 | struct pci_pbm_info *pbm) |
474 | { | 471 | { |
472 | struct pci_bus_region region; | ||
475 | struct resource *res; | 473 | struct resource *res; |
476 | u32 first, last; | 474 | u32 first, last; |
477 | u8 map; | 475 | u8 map; |
@@ -479,18 +477,18 @@ static void __devinit apb_fake_ranges(struct pci_dev *dev, | |||
479 | pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map); | 477 | pci_read_config_byte(dev, APB_IO_ADDRESS_MAP, &map); |
480 | apb_calc_first_last(map, &first, &last); | 478 | apb_calc_first_last(map, &first, &last); |
481 | res = bus->resource[0]; | 479 | res = bus->resource[0]; |
482 | res->start = (first << 21); | ||
483 | res->end = (last << 21) + ((1 << 21) - 1); | ||
484 | res->flags = IORESOURCE_IO; | 480 | res->flags = IORESOURCE_IO; |
485 | pci_resource_adjust(res, &pbm->io_space); | 481 | region.start = (first << 21); |
482 | region.end = (last << 21) + ((1 << 21) - 1); | ||
483 | pcibios_bus_to_resource(dev, res, ®ion); | ||
486 | 484 | ||
487 | pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); | 485 | pci_read_config_byte(dev, APB_MEM_ADDRESS_MAP, &map); |
488 | apb_calc_first_last(map, &first, &last); | 486 | apb_calc_first_last(map, &first, &last); |
489 | res = bus->resource[1]; | 487 | res = bus->resource[1]; |
490 | res->start = (first << 21); | ||
491 | res->end = (last << 21) + ((1 << 21) - 1); | ||
492 | res->flags = IORESOURCE_MEM; | 488 | res->flags = IORESOURCE_MEM; |
493 | pci_resource_adjust(res, &pbm->mem_space); | 489 | region.start = (first << 21); |
490 | region.end = (last << 21) + ((1 << 21) - 1); | ||
491 | pcibios_bus_to_resource(dev, res, ®ion); | ||
494 | } | 492 | } |
495 | 493 | ||
496 | static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, | 494 | static void __devinit pci_of_scan_bus(struct pci_pbm_info *pbm, |
@@ -506,6 +504,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, | |||
506 | struct pci_bus *bus; | 504 | struct pci_bus *bus; |
507 | const u32 *busrange, *ranges; | 505 | const u32 *busrange, *ranges; |
508 | int len, i, simba; | 506 | int len, i, simba; |
507 | struct pci_bus_region region; | ||
509 | struct resource *res; | 508 | struct resource *res; |
510 | unsigned int flags; | 509 | unsigned int flags; |
511 | u64 size; | 510 | u64 size; |
@@ -556,8 +555,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, | |||
556 | } | 555 | } |
557 | i = 1; | 556 | i = 1; |
558 | for (; len >= 32; len -= 32, ranges += 8) { | 557 | for (; len >= 32; len -= 32, ranges += 8) { |
559 | struct resource *root; | ||
560 | |||
561 | flags = pci_parse_of_flags(ranges[0]); | 558 | flags = pci_parse_of_flags(ranges[0]); |
562 | size = GET_64BIT(ranges, 6); | 559 | size = GET_64BIT(ranges, 6); |
563 | if (flags == 0 || size == 0) | 560 | if (flags == 0 || size == 0) |
@@ -569,7 +566,6 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, | |||
569 | " for bridge %s\n", node->full_name); | 566 | " for bridge %s\n", node->full_name); |
570 | continue; | 567 | continue; |
571 | } | 568 | } |
572 | root = &pbm->io_space; | ||
573 | } else { | 569 | } else { |
574 | if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { | 570 | if (i >= PCI_NUM_RESOURCES - PCI_BRIDGE_RESOURCES) { |
575 | printk(KERN_ERR "PCI: too many memory ranges" | 571 | printk(KERN_ERR "PCI: too many memory ranges" |
@@ -578,18 +574,12 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm, | |||
578 | } | 574 | } |
579 | res = bus->resource[i]; | 575 | res = bus->resource[i]; |
580 | ++i; | 576 | ++i; |
581 | root = &pbm->mem_space; | ||
582 | } | 577 | } |
583 | 578 | ||
584 | res->start = GET_64BIT(ranges, 1); | ||
585 | res->end = res->start + size - 1; | ||
586 | res->flags = flags; | 579 | res->flags = flags; |
587 | 580 | region.start = GET_64BIT(ranges, 1); | |
588 | /* Another way to implement this would be to add an of_device | 581 | region.end = region.start + size - 1; |
589 | * layer routine that can calculate a resource for a given | 582 | pcibios_bus_to_resource(dev, res, ®ion); |
590 | * range property value in a PCI device. | ||
591 | */ | ||
592 | pci_resource_adjust(res, root); | ||
593 | } | 583 | } |
594 | after_ranges: | 584 | after_ranges: |
595 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), | 585 | sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), |