diff options
Diffstat (limited to 'arch/ppc64/kernel/pci.c')
-rw-r--r-- | arch/ppc64/kernel/pci.c | 38 |
1 files changed, 30 insertions, 8 deletions
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c index feec06bbafc3..b2fb6746f00b 100644 --- a/arch/ppc64/kernel/pci.c +++ b/arch/ppc64/kernel/pci.c | |||
@@ -880,9 +880,9 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node, | |||
880 | } | 880 | } |
881 | 881 | ||
882 | void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | 882 | void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, |
883 | struct device_node *dev) | 883 | struct device_node *dev, int prim) |
884 | { | 884 | { |
885 | unsigned int *ranges; | 885 | unsigned int *ranges, pci_space; |
886 | unsigned long size; | 886 | unsigned long size; |
887 | int rlen = 0; | 887 | int rlen = 0; |
888 | int memno = 0; | 888 | int memno = 0; |
@@ -905,16 +905,39 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
905 | ranges = (unsigned int *) get_property(dev, "ranges", &rlen); | 905 | ranges = (unsigned int *) get_property(dev, "ranges", &rlen); |
906 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { | 906 | while ((rlen -= np * sizeof(unsigned int)) >= 0) { |
907 | res = NULL; | 907 | res = NULL; |
908 | pci_addr = (unsigned long)ranges[1] << 32 | ranges[2]; | 908 | pci_space = ranges[0]; |
909 | pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2]; | ||
909 | 910 | ||
910 | cpu_phys_addr = ranges[3]; | 911 | cpu_phys_addr = ranges[3]; |
911 | if (na == 2) | 912 | if (na >= 2) |
912 | cpu_phys_addr = cpu_phys_addr << 32 | ranges[4]; | 913 | cpu_phys_addr = (cpu_phys_addr << 32) | ranges[4]; |
913 | 914 | ||
914 | size = (unsigned long)ranges[na+3] << 32 | ranges[na+4]; | 915 | size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4]; |
916 | ranges += np; | ||
915 | if (size == 0) | 917 | if (size == 0) |
916 | continue; | 918 | continue; |
917 | switch ((ranges[0] >> 24) & 0x3) { | 919 | |
920 | /* Now consume following elements while they are contiguous */ | ||
921 | while (rlen >= np * sizeof(unsigned int)) { | ||
922 | unsigned long addr, phys; | ||
923 | |||
924 | if (ranges[0] != pci_space) | ||
925 | break; | ||
926 | addr = ((unsigned long)ranges[1] << 32) | ranges[2]; | ||
927 | phys = ranges[3]; | ||
928 | if (na >= 2) | ||
929 | phys = (phys << 32) | ranges[4]; | ||
930 | if (addr != pci_addr + size || | ||
931 | phys != cpu_phys_addr + size) | ||
932 | break; | ||
933 | |||
934 | size += ((unsigned long)ranges[na+3] << 32) | ||
935 | | ranges[na+4]; | ||
936 | ranges += np; | ||
937 | rlen -= np * sizeof(unsigned int); | ||
938 | } | ||
939 | |||
940 | switch ((pci_space >> 24) & 0x3) { | ||
918 | case 1: /* I/O space */ | 941 | case 1: /* I/O space */ |
919 | hose->io_base_phys = cpu_phys_addr; | 942 | hose->io_base_phys = cpu_phys_addr; |
920 | hose->pci_io_size = size; | 943 | hose->pci_io_size = size; |
@@ -948,7 +971,6 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose, | |||
948 | res->sibling = NULL; | 971 | res->sibling = NULL; |
949 | res->child = NULL; | 972 | res->child = NULL; |
950 | } | 973 | } |
951 | ranges += np; | ||
952 | } | 974 | } |
953 | } | 975 | } |
954 | 976 | ||