Browse Source

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>
Paul Mackerras 19 years ago
parent
commit
f7abbc190b

+ 1 - 1
arch/ppc64/kernel/maple_pci.c

@@ -359,7 +359,7 @@ static int __init add_bridge(struct device_node *dev)
 
 	/* 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 */

+ 30 - 8
arch/ppc64/kernel/pci.c

@@ -880,9 +880,9 @@ static void __devinit pci_process_ISA_OF_ranges(struct device_node *isa_node,
 }
 
 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 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
 	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 @@ void __devinit pci_process_bridge_OF_ranges(struct pci_controller *hose,
 			res->sibling = NULL;
 			res->child = NULL;
 		}
-		ranges += np;
 	}
 }
 

+ 2 - 2
arch/ppc64/kernel/rtas_pci.c

@@ -400,7 +400,7 @@ unsigned long __init find_and_init_phbs(void)
 		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 @@ struct pci_controller * __devinit init_phb_dynamic(struct device_node *dn)
 	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);

+ 1 - 1
include/asm-ppc64/pci-bridge.h

@@ -123,7 +123,7 @@ static inline struct device_node *pci_bus_to_OF_node(struct pci_bus *bus)
 }
 
 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);