ppc64: Add a `primary' argument to pci_process_bridge_OF_ranges

... for consistency with ppc32 and to make the powermac merge easier.
Also make it use just a single resource in the host bridge for multiple
consecutive elements of the ranges property.

Signed-off-by: Paul Mackerras <paulus@samba.org>
diff --git a/arch/ppc64/kernel/maple_pci.c b/arch/ppc64/kernel/maple_pci.c
index b901470..633324b 100644
--- a/arch/ppc64/kernel/maple_pci.c
+++ b/arch/ppc64/kernel/maple_pci.c
@@ -359,7 +359,7 @@
 
 	/* Interpret the "ranges" property */
 	/* This also maps the I/O region and sets isa_io/mem_base */
-	pci_process_bridge_OF_ranges(hose, dev);
+	pci_process_bridge_OF_ranges(hose, dev, primary);
 	pci_setup_phb_io(hose, primary);
 
 	/* Fixup "bus-range" OF property */
diff --git a/arch/ppc64/kernel/pci.c b/arch/ppc64/kernel/pci.c
index feec06b..b2fb674 100644
--- a/arch/ppc64/kernel/pci.c
+++ b/arch/ppc64/kernel/pci.c
@@ -880,9 +880,9 @@
 }
 
 void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
-					    struct device_node *dev)
+					    struct device_node *dev, int prim)
 {
-	unsigned int *ranges;
+	unsigned int *ranges, pci_space;
 	unsigned long size;
 	int rlen = 0;
 	int memno = 0;
@@ -905,16 +905,39 @@
 	ranges = (unsigned int *) get_property(dev, "ranges", &rlen);
 	while ((rlen -= np * sizeof(unsigned int)) >= 0) {
 		res = NULL;
-		pci_addr = (unsigned long)ranges[1] << 32 | ranges[2];
+		pci_space = ranges[0];
+		pci_addr = ((unsigned long)ranges[1] << 32) | ranges[2];
 
 		cpu_phys_addr = ranges[3];
-		if (na == 2)
-			cpu_phys_addr = cpu_phys_addr << 32 | ranges[4];
+		if (na >= 2)
+			cpu_phys_addr = (cpu_phys_addr << 32) | ranges[4];
 
-		size = (unsigned long)ranges[na+3] << 32 | ranges[na+4];
+		size = ((unsigned long)ranges[na+3] << 32) | ranges[na+4];
+		ranges += np;
 		if (size == 0)
 			continue;
-		switch ((ranges[0] >> 24) & 0x3) {
+
+		/* Now consume following elements while they are contiguous */
+		while (rlen >= np * sizeof(unsigned int)) {
+			unsigned long addr, phys;
+
+			if (ranges[0] != pci_space)
+				break;
+			addr = ((unsigned long)ranges[1] << 32) | ranges[2];
+			phys = ranges[3];
+			if (na >= 2)
+				phys = (phys << 32) | ranges[4];
+			if (addr != pci_addr + size ||
+			    phys != cpu_phys_addr + size)
+				break;
+
+			size += ((unsigned long)ranges[na+3] << 32)
+				| ranges[na+4];
+			ranges += np;
+			rlen -= np * sizeof(unsigned int);
+		}
+
+		switch ((pci_space >> 24) & 0x3) {
 		case 1:		/* I/O space */
 			hose->io_base_phys = cpu_phys_addr;
 			hose->pci_io_size = size;
@@ -948,7 +971,6 @@
 			res->sibling = NULL;
 			res->child = NULL;
 		}
-		ranges += np;
 	}
 }
 
diff --git a/arch/ppc64/kernel/rtas_pci.c b/arch/ppc64/kernel/rtas_pci.c
index 20361bc..3ad15c9 100644
--- a/arch/ppc64/kernel/rtas_pci.c
+++ b/arch/ppc64/kernel/rtas_pci.c
@@ -400,7 +400,7 @@
 		if (!phb)
 			continue;
 
-		pci_process_bridge_OF_ranges(phb, node);
+		pci_process_bridge_OF_ranges(phb, node, 0);
 		pci_setup_phb_io(phb, index == 0);
 #ifdef CONFIG_PPC_PSERIES
 		if (ppc64_interrupt_controller == IC_OPEN_PIC && pSeries_mpic) {
@@ -450,7 +450,7 @@
 	if (!phb)
 		return NULL;
 
-	pci_process_bridge_OF_ranges(phb, dn);
+	pci_process_bridge_OF_ranges(phb, dn, primary);
 
 	pci_setup_phb_io_dynamic(phb, primary);
 	of_node_put(root);
diff --git a/include/asm-ppc64/pci-bridge.h b/include/asm-ppc64/pci-bridge.h
index 7d8ecb5..60cf8c8 100644
--- a/include/asm-ppc64/pci-bridge.h
+++ b/include/asm-ppc64/pci-bridge.h
@@ -123,7 +123,7 @@
 }
 
 extern void pci_process_bridge_OF_ranges(struct pci_controller *hose,
-					 struct device_node *dev);
+					 struct device_node *dev, int primary);
 
 extern int pcibios_remove_root_bus(struct pci_controller *phb);