diff options
Diffstat (limited to 'arch/powerpc/kernel/pci-common.c')
-rw-r--r-- | arch/powerpc/kernel/pci-common.c | 130 |
1 files changed, 130 insertions, 0 deletions
diff --git a/arch/powerpc/kernel/pci-common.c b/arch/powerpc/kernel/pci-common.c index 0245c989d30a..c61e9324f770 100644 --- a/arch/powerpc/kernel/pci-common.c +++ b/arch/powerpc/kernel/pci-common.c | |||
@@ -691,3 +691,133 @@ void pcibios_bus_to_resource(struct pci_dev *dev, struct resource *res, | |||
691 | res->end = (region->end + offset) & mask; | 691 | res->end = (region->end + offset) & mask; |
692 | } | 692 | } |
693 | EXPORT_SYMBOL(pcibios_bus_to_resource); | 693 | EXPORT_SYMBOL(pcibios_bus_to_resource); |
694 | |||
695 | /* Fixup a bus resource into a linux resource */ | ||
696 | static void __devinit fixup_resource(struct resource *res, struct pci_dev *dev) | ||
697 | { | ||
698 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
699 | resource_size_t offset = 0, mask = (resource_size_t)-1; | ||
700 | |||
701 | if (res->flags & IORESOURCE_IO) { | ||
702 | offset = (unsigned long)hose->io_base_virt - _IO_BASE; | ||
703 | mask = 0xffffffffu; | ||
704 | } else if (res->flags & IORESOURCE_MEM) | ||
705 | offset = hose->pci_mem_offset; | ||
706 | |||
707 | res->start = (res->start + offset) & mask; | ||
708 | res->end = (res->end + offset) & mask; | ||
709 | |||
710 | pr_debug("PCI:%s %016llx-%016llx\n", | ||
711 | pci_name(dev), | ||
712 | (unsigned long long)res->start, | ||
713 | (unsigned long long)res->end); | ||
714 | } | ||
715 | |||
716 | |||
717 | /* This header fixup will do the resource fixup for all devices as they are | ||
718 | * probed, but not for bridge ranges | ||
719 | */ | ||
720 | static void __devinit pcibios_fixup_resources(struct pci_dev *dev) | ||
721 | { | ||
722 | struct pci_controller *hose = pci_bus_to_host(dev->bus); | ||
723 | int i; | ||
724 | |||
725 | if (!hose) { | ||
726 | printk(KERN_ERR "No host bridge for PCI dev %s !\n", | ||
727 | pci_name(dev)); | ||
728 | return; | ||
729 | } | ||
730 | for (i = 0; i < DEVICE_COUNT_RESOURCE; i++) { | ||
731 | struct resource *res = dev->resource + i; | ||
732 | if (!res->flags) | ||
733 | continue; | ||
734 | if (res->end == 0xffffffff) { | ||
735 | pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] is unassigned\n", | ||
736 | pci_name(dev), i, | ||
737 | (unsigned long long)res->start, | ||
738 | (unsigned long long)res->end, | ||
739 | (unsigned int)res->flags); | ||
740 | res->end -= res->start; | ||
741 | res->start = 0; | ||
742 | res->flags |= IORESOURCE_UNSET; | ||
743 | continue; | ||
744 | } | ||
745 | |||
746 | pr_debug("PCI:%s Resource %d %016llx-%016llx [%x] fixup...\n", | ||
747 | pci_name(dev), i, | ||
748 | (unsigned long long)res->start,\ | ||
749 | (unsigned long long)res->end, | ||
750 | (unsigned int)res->flags); | ||
751 | |||
752 | fixup_resource(res, dev); | ||
753 | } | ||
754 | |||
755 | /* Call machine specific resource fixup */ | ||
756 | if (ppc_md.pcibios_fixup_resources) | ||
757 | ppc_md.pcibios_fixup_resources(dev); | ||
758 | } | ||
759 | DECLARE_PCI_FIXUP_HEADER(PCI_ANY_ID, PCI_ANY_ID, pcibios_fixup_resources); | ||
760 | |||
761 | static void __devinit __pcibios_fixup_bus(struct pci_bus *bus) | ||
762 | { | ||
763 | struct pci_dev *dev = bus->self; | ||
764 | |||
765 | pr_debug("PCI: Fixup bus %d (%s)\n", bus->number, dev ? pci_name(dev) : "PHB"); | ||
766 | |||
767 | /* Fixup PCI<->PCI bridges. Host bridges are handled separately, for | ||
768 | * now differently between 32 and 64 bits. | ||
769 | */ | ||
770 | if (dev != NULL) { | ||
771 | struct resource *res; | ||
772 | int i; | ||
773 | |||
774 | for (i = 0; i < PCI_BUS_NUM_RESOURCES; ++i) { | ||
775 | if ((res = bus->resource[i]) == NULL) | ||
776 | continue; | ||
777 | if (!res->flags || bus->self->transparent) | ||
778 | continue; | ||
779 | |||
780 | pr_debug("PCI:%s Bus rsrc %d %016llx-%016llx [%x] fixup...\n", | ||
781 | pci_name(dev), i, | ||
782 | (unsigned long long)res->start,\ | ||
783 | (unsigned long long)res->end, | ||
784 | (unsigned int)res->flags); | ||
785 | |||
786 | fixup_resource(res, dev); | ||
787 | } | ||
788 | } | ||
789 | |||
790 | /* Additional setup that is different between 32 and 64 bits for now */ | ||
791 | pcibios_do_bus_setup(bus); | ||
792 | |||
793 | /* Platform specific bus fixups */ | ||
794 | if (ppc_md.pcibios_fixup_bus) | ||
795 | ppc_md.pcibios_fixup_bus(bus); | ||
796 | |||
797 | /* Read default IRQs and fixup if necessary */ | ||
798 | list_for_each_entry(dev, &bus->devices, bus_list) { | ||
799 | pci_read_irq_line(dev); | ||
800 | if (ppc_md.pci_irq_fixup) | ||
801 | ppc_md.pci_irq_fixup(dev); | ||
802 | } | ||
803 | } | ||
804 | |||
805 | void __devinit pcibios_fixup_bus(struct pci_bus *bus) | ||
806 | { | ||
807 | /* When called from the generic PCI probe, read PCI<->PCI bridge | ||
808 | * bases before proceeding | ||
809 | */ | ||
810 | if (bus->self != NULL) | ||
811 | pci_read_bridge_bases(bus); | ||
812 | __pcibios_fixup_bus(bus); | ||
813 | } | ||
814 | EXPORT_SYMBOL(pcibios_fixup_bus); | ||
815 | |||
816 | /* When building a bus from the OF tree rather than probing, we need a | ||
817 | * slightly different version of the fixup which doesn't read the | ||
818 | * bridge bases using config space accesses | ||
819 | */ | ||
820 | void __devinit pcibios_fixup_of_probed_bus(struct pci_bus *bus) | ||
821 | { | ||
822 | __pcibios_fixup_bus(bus); | ||
823 | } | ||