aboutsummaryrefslogtreecommitdiffstats
path: root/arch/sparc64/kernel/pci.c
diff options
context:
space:
mode:
authorDavid S. Miller <davem@sunset.davemloft.net>2007-06-08 00:59:44 -0400
committerDavid S. Miller <davem@sunset.davemloft.net>2007-06-08 00:59:44 -0400
commit8c2786cfa6d15c474ec7030e8161c88e9b5c597d (patch)
tree403d0c6a52361717a54d3dbaa15d6db87f3627e5 /arch/sparc64/kernel/pci.c
parentea1ff19ce0146a3982a6ded4274122e6d0a91bed (diff)
[SPARC64]: Handle PCI bridges without 'ranges' property.
This fixes the IDE controller not showing up on Netra-T1 systems. Just like Simba bridges, some PCI bridges can lack the 'ranges' OBP property. So we handle this similarly to the existing Simba code: 1) In of_device register address resolving, we push the translation to the parent. 2) In PCI device scanning, we interrogate the PCI config space registers of the PCI bus device in order to resolve the resources, just like the generic Linux PCI probing code does. With much help and testing from Fabio, who also reported the initial problem. Signed-off-by: David S. Miller <davem@davemloft.net> Signed-off-by: Fabio Massimo Di Nitto <fabbione@ubuntu.com>
Diffstat (limited to 'arch/sparc64/kernel/pci.c')
-rw-r--r--arch/sparc64/kernel/pci.c97
1 files changed, 89 insertions, 8 deletions
diff --git a/arch/sparc64/kernel/pci.c b/arch/sparc64/kernel/pci.c
index 38a32bc95d22..81f4a5ea05f7 100644
--- a/arch/sparc64/kernel/pci.c
+++ b/arch/sparc64/kernel/pci.c
@@ -522,6 +522,89 @@ static void pci_resource_adjust(struct resource *res,
522 res->end += root->start; 522 res->end += root->start;
523} 523}
524 524
525/* For PCI bus devices which lack a 'ranges' property we interrogate
526 * the config space values to set the resources, just like the generic
527 * Linux PCI probing code does.
528 */
529static void __devinit pci_cfg_fake_ranges(struct pci_dev *dev,
530 struct pci_bus *bus,
531 struct pci_pbm_info *pbm)
532{
533 struct resource *res;
534 u8 io_base_lo, io_limit_lo;
535 u16 mem_base_lo, mem_limit_lo;
536 unsigned long base, limit;
537
538 pci_read_config_byte(dev, PCI_IO_BASE, &io_base_lo);
539 pci_read_config_byte(dev, PCI_IO_LIMIT, &io_limit_lo);
540 base = (io_base_lo & PCI_IO_RANGE_MASK) << 8;
541 limit = (io_limit_lo & PCI_IO_RANGE_MASK) << 8;
542
543 if ((io_base_lo & PCI_IO_RANGE_TYPE_MASK) == PCI_IO_RANGE_TYPE_32) {
544 u16 io_base_hi, io_limit_hi;
545
546 pci_read_config_word(dev, PCI_IO_BASE_UPPER16, &io_base_hi);
547 pci_read_config_word(dev, PCI_IO_LIMIT_UPPER16, &io_limit_hi);
548 base |= (io_base_hi << 16);
549 limit |= (io_limit_hi << 16);
550 }
551
552 res = bus->resource[0];
553 if (base <= limit) {
554 res->flags = (io_base_lo & PCI_IO_RANGE_TYPE_MASK) | IORESOURCE_IO;
555 if (!res->start)
556 res->start = base;
557 if (!res->end)
558 res->end = limit + 0xfff;
559 pci_resource_adjust(res, &pbm->io_space);
560 }
561
562 pci_read_config_word(dev, PCI_MEMORY_BASE, &mem_base_lo);
563 pci_read_config_word(dev, PCI_MEMORY_LIMIT, &mem_limit_lo);
564 base = (mem_base_lo & PCI_MEMORY_RANGE_MASK) << 16;
565 limit = (mem_limit_lo & PCI_MEMORY_RANGE_MASK) << 16;
566
567 res = bus->resource[1];
568 if (base <= limit) {
569 res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
570 IORESOURCE_MEM);
571 res->start = base;
572 res->end = limit + 0xfffff;
573 pci_resource_adjust(res, &pbm->mem_space);
574 }
575
576 pci_read_config_word(dev, PCI_PREF_MEMORY_BASE, &mem_base_lo);
577 pci_read_config_word(dev, PCI_PREF_MEMORY_LIMIT, &mem_limit_lo);
578 base = (mem_base_lo & PCI_PREF_RANGE_MASK) << 16;
579 limit = (mem_limit_lo & PCI_PREF_RANGE_MASK) << 16;
580
581 if ((mem_base_lo & PCI_PREF_RANGE_TYPE_MASK) == PCI_PREF_RANGE_TYPE_64) {
582 u32 mem_base_hi, mem_limit_hi;
583
584 pci_read_config_dword(dev, PCI_PREF_BASE_UPPER32, &mem_base_hi);
585 pci_read_config_dword(dev, PCI_PREF_LIMIT_UPPER32, &mem_limit_hi);
586
587 /*
588 * Some bridges set the base > limit by default, and some
589 * (broken) BIOSes do not initialize them. If we find
590 * this, just assume they are not being used.
591 */
592 if (mem_base_hi <= mem_limit_hi) {
593 base |= ((long) mem_base_hi) << 32;
594 limit |= ((long) mem_limit_hi) << 32;
595 }
596 }
597
598 res = bus->resource[2];
599 if (base <= limit) {
600 res->flags = ((mem_base_lo & PCI_MEMORY_RANGE_TYPE_MASK) |
601 IORESOURCE_MEM | IORESOURCE_PREFETCH);
602 res->start = base;
603 res->end = limit + 0xfffff;
604 pci_resource_adjust(res, &pbm->mem_space);
605 }
606}
607
525/* Cook up fake bus resources for SUNW,simba PCI bridges which lack 608/* Cook up fake bus resources for SUNW,simba PCI bridges which lack
526 * a proper 'ranges' property. 609 * a proper 'ranges' property.
527 */ 610 */
@@ -581,13 +664,8 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
581 simba = 0; 664 simba = 0;
582 if (ranges == NULL) { 665 if (ranges == NULL) {
583 const char *model = of_get_property(node, "model", NULL); 666 const char *model = of_get_property(node, "model", NULL);
584 if (model && !strcmp(model, "SUNW,simba")) { 667 if (model && !strcmp(model, "SUNW,simba"))
585 simba = 1; 668 simba = 1;
586 } else {
587 printk(KERN_DEBUG "Can't get ranges for PCI-PCI bridge %s\n",
588 node->full_name);
589 return;
590 }
591 } 669 }
592 670
593 bus = pci_add_new_bus(dev->bus, dev, busrange[0]); 671 bus = pci_add_new_bus(dev->bus, dev, busrange[0]);
@@ -611,7 +689,10 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
611 } 689 }
612 if (simba) { 690 if (simba) {
613 apb_fake_ranges(dev, bus, pbm); 691 apb_fake_ranges(dev, bus, pbm);
614 goto simba_cont; 692 goto after_ranges;
693 } else if (ranges == NULL) {
694 pci_cfg_fake_ranges(dev, bus, pbm);
695 goto after_ranges;
615 } 696 }
616 i = 1; 697 i = 1;
617 for (; len >= 32; len -= 32, ranges += 8) { 698 for (; len >= 32; len -= 32, ranges += 8) {
@@ -650,7 +731,7 @@ static void __devinit of_scan_pci_bridge(struct pci_pbm_info *pbm,
650 */ 731 */
651 pci_resource_adjust(res, root); 732 pci_resource_adjust(res, root);
652 } 733 }
653simba_cont: 734after_ranges:
654 sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus), 735 sprintf(bus->name, "PCI Bus %04x:%02x", pci_domain_nr(bus),
655 bus->number); 736 bus->number);
656 if (ofpci_verbose) 737 if (ofpci_verbose)