[PATCH] powerpc: Support new property called interrupt-parents

Stuart Yoder b08248 at freescale.com
Wed Mar 21 06:17:24 EST 2007


Support new property called interrupt-parents.  This enables the
description of devices that have multiple interrupts that are routed to
different interrupt controllers.

Signed-off-by: Stuart Yoder <stuart.yoder at freescale.com>
---

-The booting-without-of.txt changes were reviewed and
 discussed on the list in late Feb

-The code change to support this is isolated to of_irq_map_one().
 If the normal interrupt-parent is present everything behaves as
 before.  If the interrupt-parents property is specified, the index
 argument is used to identify the interrupt parent.  In order
 to parse the interrupts property the interrupt tree has to be
 traversed for each interrupt parent to determine the correct
 #interrupt-cells value.

-I've done some limited testing using a network device on a Freescale
 board.

 Documentation/powerpc/booting-without-of.txt |   60 ++++++++++++++++-
 arch/powerpc/kernel/prom_parse.c             |   96 +++++++++++++++++++------
 2 files changed, 132 insertions(+), 24 deletions(-)

diff --git a/Documentation/powerpc/booting-without-of.txt b/Documentation/powerpc/booting-without-of.txt
index a1f83f1..8a1c311 100644
--- a/Documentation/powerpc/booting-without-of.txt
+++ b/Documentation/powerpc/booting-without-of.txt
@@ -1769,7 +1769,65 @@ If the interrupt-parent property is not defined for a node, it's
 interrupt parent is assumed to be an ancestor in the node's
 _device tree_ hierarchy.
 
-3) OpenPIC Interrupt Controllers
+3) interrupt-parents property
+-----------------------------
+
+For devices that generate interrupts to multiple interrupt
+controllers, the  interrupt-parent representation
+is not sufficient because it only describes a single
+interrupt parent. The 'interrupt-parents' property can be used
+to represent this (note the plural in the property name).
+
+The interrupt-parents property consists of one or more 
+interrupt parent phandle values each representing the interrupt
+parent for the corresponding interrupt specifier in the interrupts
+property:
+
+  interrupt-parents = <parent-phandle0 parent-phandle1 ... parent-phandleN>
+  interrupts = <int-specifier0 int-specifier1 ... int-specifierN>
+
+It is required that the number of interrupts encoded in the interrupt-parents
+property exacly match the number of interrupt specifiers in the interrupts
+property.
+
+See the example below:
+
+   pic0: pic at 700 {
+       interrupt-controller;
+       #address-cells = <0>;
+       #interrupt-cells = <2>;
+       reg = <700 100>;
+       device_type = "open-pic";
+   };
+
+   pic1: pic at 800 {
+       interrupt-controller;
+       #address-cells = <0>;
+       #interrupt-cells = <2>;
+       reg = <800 100>;
+       device_type = "open-pic";
+   };
+
+   ethernet at 25000 {
+       device_type = "network";
+       reg = <25000 1000>;
+       ...
+       interrupt-parents = <&pic0 &pic0 &pic1>;
+       interrupts        = <13 3  14 3  18 3>;
+   };
+
+In the above example, the interrupts property and the interrupt-parents
+property defines three interrupts. The first 2 interrupt lines are
+routed to irqs 0x13 and 0x14 on pic0.  The 3rd interrupt line is 
+routed to irq 0x18 on pic1.
+
+Note: each interrupt parent in the interrupt-parents array can
+potentially specify a different value for #interrupt-cells.  The number
+of #interrupt-cells for each parent must be determined to correctly
+parse the interrupts property.
+
+
+4) OpenPIC Interrupt Controllers
 --------------------------------
 
 OpenPIC interrupt controllers require 2 cells to encode
diff --git a/arch/powerpc/kernel/prom_parse.c b/arch/powerpc/kernel/prom_parse.c
index 91b443c..8cf7e96 100644
--- a/arch/powerpc/kernel/prom_parse.c
+++ b/arch/powerpc/kernel/prom_parse.c
@@ -958,10 +958,11 @@ static int of_irq_map_oldworld(struct device_node *device, int index,
 
 int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq)
 {
-	struct device_node *p;
-	const u32 *intspec, *tmp, *addr;
-	u32 intsize, intlen;
-	int res;
+	struct device_node *p = NULL;
+	const u32 *intspec, *intprop, *intp, *tmp, *addr, *parp;
+	u32 intsize = 0;
+	u32 intlen, intplen;
+	int res,i;
 
 	DBG("of_irq_map_one: dev=%s, index=%d\n", device->full_name, index);
 
@@ -970,36 +971,85 @@ int of_irq_map_one(struct device_node *device, int index, struct of_irq *out_irq
 		return of_irq_map_oldworld(device, index, out_irq);
 
 	/* Get the interrupts property */
-	intspec = get_property(device, "interrupts", &intlen);
-	if (intspec == NULL)
+	intprop = get_property(device, "interrupts", &intlen);
+	if (intprop == NULL)
 		return -EINVAL;
 	intlen /= sizeof(u32);
 
 	/* Get the reg property (if any) */
 	addr = get_property(device, "reg", NULL);
 
-	/* Look for the interrupt parent. */
-	p = of_irq_find_parent(device);
-	if (p == NULL)
-		return -EINVAL;
+	/* look for interrupt-parents */
+	intp = get_property(device, "interrupt-parents", &intplen);
+	if (intp == NULL) {
 
-	/* Get size of interrupt specifier */
-	tmp = get_property(p, "#interrupt-cells", NULL);
-	if (tmp == NULL) {
-		of_node_put(p);
-		return -EINVAL;
-	}
-	intsize = *tmp;
+		/* Look for the interrupt parent. */
+		p = of_irq_find_parent(device);
+		if (p == NULL)
+			return -EINVAL;
 
-	DBG(" intsize=%d intlen=%d\n", intsize, intlen);
+		/* Get size of interrupt specifier */
+		tmp = get_property(p, "#interrupt-cells", NULL);
+		if (tmp == NULL) {
+			of_node_put(p);
+			return -EINVAL;
+		}
+		intsize = *tmp;
+	
+		DBG(" intsize=%d intlen=%d\n", intsize, intlen);
+	
+		/* Check index */
+		if ((index + 1) * intsize > intlen)
+			return -EINVAL;
 
-	/* Check index */
-	if ((index + 1) * intsize > intlen)
-		return -EINVAL;
+		/* compute pointer to interrupt specifier */
+		intspec = intprop + index * intsize;
+
+	} else {  /* this node has multiple interrupt parents */
+
+		intplen /= sizeof(u32); /* # of cells */
+
+		if ((index+1) > intplen)
+			return -EINVAL; /* index is out of bounds */
+
+		intspec = intprop;
+
+		for (i=0; i < intplen; i++) {
+
+			p = of_find_node_by_phandle(intp[i]);
+
+			/* starting with the specified int parent, search up the int tree for interrupt-cells */
+			while (p && get_property(p, "#interrupt-cells", NULL) == NULL) {
+
+				parp = get_property(p, "interrupt-parent", NULL);
+				if (parp == NULL) {
+					p = of_get_parent(p);
+				} else {
+					p = of_find_node_by_phandle(*parp);
+				}
+			}
+
+			/* Get size of interrupt specifier */
+			tmp = get_property(p, "#interrupt-cells", NULL);
+			if (tmp == NULL) {
+				of_node_put(p);
+				return -EINVAL;
+			}
+			intsize = *tmp;
+
+			if (index == i)
+				break;
+
+			/* advance pointer to next int specifier */
+			intspec = intspec + intsize;
+		}
+
+		DBG(" index=%d intspec[0]=%d intsize=%d \n", i, *intspec, intsize);
+
+	}
 
 	/* Get new specifier and map it */
-	res = of_irq_map_raw(p, intspec + index * intsize, intsize,
-			     addr, out_irq);
+	res = of_irq_map_raw(p, intspec, intsize, addr, out_irq);
 	of_node_put(p);
 	return res;
 }
-- 
1.5.0.3




More information about the Linuxppc-dev mailing list