powerpc/mpic: Add in-core support for cascaded MPICs
authorKyle Moffett <Kyle.D.Moffett@boeing.com>
Fri, 2 Dec 2011 06:28:07 +0000 (06:28 +0000)
committerBenjamin Herrenschmidt <benh@kernel.crashing.org>
Wed, 7 Dec 2011 02:43:09 +0000 (13:43 +1100)
The Cell and PowerMac platforms use virtually identical cascaded-IRQ
setup code, so just merge it into the core.  Ideally this code would
trigger automatically when an MPIC device-node specifies an "interrupts"
property, perhaps even enabling MPIC_SECONDARY along the way.

Unfortunately, Benjamin Herrenschmidt has had bad experiences in the
past with the quality of Apple PowerMac device-trees, so to be safe we
will only try to parse out an IRQ if the MPIC_SECONDARY flag is set by
the caller.

Signed-off-by: Kyle Moffett <Kyle.D.Moffett@boeing.com>
Signed-off-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
arch/powerpc/platforms/cell/setup.c
arch/powerpc/platforms/powermac/pic.c
arch/powerpc/sysdev/mpic.c

index cd00ca8..62002a7 100644 (file)
@@ -184,24 +184,10 @@ static int __init cell_publish_devices(void)
 }
 machine_subsys_initcall(cell, cell_publish_devices);
 
-static void cell_mpic_cascade(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct mpic *mpic = irq_desc_get_handler_data(desc);
-       unsigned int virq;
-
-       virq = mpic_get_one_irq(mpic);
-       if (virq != NO_IRQ)
-               generic_handle_irq(virq);
-
-       chip->irq_eoi(&desc->irq_data);
-}
-
 static void __init mpic_init_IRQ(void)
 {
        struct device_node *dn;
        struct mpic *mpic;
-       unsigned int virq;
 
        for (dn = NULL;
             (dn = of_find_node_by_name(dn, "interrupt-controller"));) {
@@ -215,15 +201,6 @@ static void __init mpic_init_IRQ(void)
                if (mpic == NULL)
                        continue;
                mpic_init(mpic);
-
-               virq = irq_of_parse_and_map(dn, 0);
-               if (virq == NO_IRQ)
-                       continue;
-
-               printk(KERN_INFO "%s : hooking up to IRQ %d\n",
-                      dn->full_name, virq);
-               irq_set_handler_data(virq, mpic);
-               irq_set_chained_handler(virq, cell_mpic_cascade);
        }
 }
 
index b962101..d8aedf1 100644 (file)
@@ -464,18 +464,6 @@ int of_irq_map_oldworld(struct device_node *device, int index,
 }
 #endif /* CONFIG_PPC32 */
 
-static void pmac_u3_cascade(unsigned int irq, struct irq_desc *desc)
-{
-       struct irq_chip *chip = irq_desc_get_chip(desc);
-       struct mpic *mpic = irq_desc_get_handler_data(desc);
-       unsigned int cascade_irq = mpic_get_one_irq(mpic);
-
-       if (cascade_irq != NO_IRQ)
-               generic_handle_irq(cascade_irq);
-
-       chip->irq_eoi(&desc->irq_data);
-}
-
 static void __init pmac_pic_setup_mpic_nmi(struct mpic *mpic)
 {
 #if defined(CONFIG_XMON) && defined(CONFIG_PPC32)
@@ -526,7 +514,6 @@ static int __init pmac_pic_probe_mpic(void)
 {
        struct mpic *mpic1, *mpic2;
        struct device_node *np, *master = NULL, *slave = NULL;
-       unsigned int cascade;
 
        /* We can have up to 2 MPICs cascaded */
        for (np = NULL; (np = of_find_node_by_type(np, "open-pic"))
@@ -562,27 +549,14 @@ static int __init pmac_pic_probe_mpic(void)
 
        of_node_put(master);
 
-       /* No slave, let's go out */
-       if (slave == NULL)
-               return 0;
-
-       /* Get/Map slave interrupt */
-       cascade = irq_of_parse_and_map(slave, 0);
-       if (cascade == NO_IRQ) {
-               printk(KERN_ERR "Failed to map cascade IRQ\n");
-               return 0;
-       }
-
-       mpic2 = pmac_setup_one_mpic(slave, 0);
-       if (mpic2 == NULL) {
-               printk(KERN_ERR "Failed to setup slave MPIC\n");
+       /* Set up a cascaded controller, if present */
+       if (slave) {
+               mpic2 = pmac_setup_one_mpic(slave, 0);
+               if (mpic2 == NULL)
+                       printk(KERN_ERR "Failed to setup slave MPIC\n");
                of_node_put(slave);
-               return 0;
        }
-       irq_set_handler_data(cascade, mpic2);
-       irq_set_chained_handler(cascade, pmac_u3_cascade);
 
-       of_node_put(slave);
        return 0;
 }
 
index 7611060..4e9ccb1 100644 (file)
@@ -1111,6 +1111,22 @@ static int mpic_host_xlate(struct irq_host *h, struct device_node *ct,
        return 0;
 }
 
+/* IRQ handler for a secondary MPIC cascaded from another IRQ controller */
+static void mpic_cascade(unsigned int irq, struct irq_desc *desc)
+{
+       struct irq_chip *chip = irq_desc_get_chip(desc);
+       struct mpic *mpic = irq_desc_get_handler_data(desc);
+       unsigned int virq;
+
+       BUG_ON(!(mpic->flags & MPIC_SECONDARY));
+
+       virq = mpic_get_one_irq(mpic);
+       if (virq != NO_IRQ)
+               generic_handle_irq(virq);
+
+       chip->irq_eoi(&desc->irq_data);
+}
+
 static struct irq_host_ops mpic_host_ops = {
        .match = mpic_host_match,
        .map = mpic_host_map,
@@ -1402,8 +1418,7 @@ void __init mpic_set_default_senses(struct mpic *mpic, u8 *senses, int count)
 
 void __init mpic_init(struct mpic *mpic)
 {
-       int i;
-       int cpu;
+       int i, cpu;
 
        BUG_ON(mpic->num_sources == 0);
 
@@ -1488,6 +1503,17 @@ void __init mpic_init(struct mpic *mpic)
                                  GFP_KERNEL);
        BUG_ON(mpic->save_data == NULL);
 #endif
+
+       /* Check if this MPIC is chained from a parent interrupt controller */
+       if (mpic->flags & MPIC_SECONDARY) {
+               int virq = irq_of_parse_and_map(mpic->node, 0);
+               if (virq != NO_IRQ) {
+                       printk(KERN_INFO "%s: hooking up to IRQ %d\n",
+                                       mpic->node->full_name, virq);
+                       irq_set_handler_data(virq, mpic);
+                       irq_set_chained_handler(virq, &mpic_cascade);
+               }
+       }
 }
 
 void __init mpic_set_clk_ratio(struct mpic *mpic, u32 clock_ratio)