diff options
Diffstat (limited to 'arch/sparc64')
-rw-r--r-- | arch/sparc64/kernel/of_device.c | 19 | ||||
-rw-r--r-- | arch/sparc64/kernel/pci.c | 97 |
2 files changed, 103 insertions, 13 deletions
diff --git a/arch/sparc64/kernel/of_device.c b/arch/sparc64/kernel/of_device.c index 16cc46a71872..6676b93219dc 100644 --- a/arch/sparc64/kernel/of_device.c +++ b/arch/sparc64/kernel/of_device.c | |||
@@ -343,6 +343,15 @@ static int of_bus_simba_match(struct device_node *np) | |||
343 | 343 | ||
344 | if (model && !strcmp(model, "SUNW,simba")) | 344 | if (model && !strcmp(model, "SUNW,simba")) |
345 | return 1; | 345 | return 1; |
346 | |||
347 | /* Treat PCI busses lacking ranges property just like | ||
348 | * simba. | ||
349 | */ | ||
350 | if (!strcmp(np->type, "pci") || !strcmp(np->type, "pciex")) { | ||
351 | if (!of_find_property(np, "ranges", NULL)) | ||
352 | return 1; | ||
353 | } | ||
354 | |||
346 | return 0; | 355 | return 0; |
347 | } | 356 | } |
348 | 357 | ||
@@ -549,8 +558,6 @@ static int __init build_one_resource(struct device_node *parent, | |||
549 | 558 | ||
550 | static int __init use_1to1_mapping(struct device_node *pp) | 559 | static int __init use_1to1_mapping(struct device_node *pp) |
551 | { | 560 | { |
552 | const char *model; | ||
553 | |||
554 | /* If this is on the PMU bus, don't try to translate it even | 561 | /* If this is on the PMU bus, don't try to translate it even |
555 | * if a ranges property exists. | 562 | * if a ranges property exists. |
556 | */ | 563 | */ |
@@ -567,9 +574,11 @@ static int __init use_1to1_mapping(struct device_node *pp) | |||
567 | if (!strcmp(pp->name, "dma")) | 574 | if (!strcmp(pp->name, "dma")) |
568 | return 0; | 575 | return 0; |
569 | 576 | ||
570 | /* Similarly for Simba PCI bridges. */ | 577 | /* Similarly for all PCI bridges, if we get this far |
571 | model = of_get_property(pp, "model", NULL); | 578 | * it lacks a ranges property, and this will include |
572 | if (model && !strcmp(model, "SUNW,simba")) | 579 | * cases like Simba. |
580 | */ | ||
581 | if (!strcmp(pp->type, "pci") || !strcmp(pp->type, "pciex")) | ||
573 | return 0; | 582 | return 0; |
574 | 583 | ||
575 | return 1; | 584 | return 1; |
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 | */ | ||
529 | static 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 | } |
653 | simba_cont: | 734 | after_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) |