[POWERPC] QEIC: Implement pluggable handlers, fix MPIC cascading
authorAnton Vorontsov <avorontsov@ru.mvista.com>
Fri, 5 Oct 2007 17:47:29 +0000 (21:47 +0400)
committerKumar Gala <galak@kernel.crashing.org>
Mon, 8 Oct 2007 13:38:57 +0000 (08:38 -0500)
set_irq_chained_handler overwrites MPIC's handle_irq function
(handle_fasteoi_irq) thus MPIC never gets eoi event from the
cascaded IRQ. This situation hangs MPIC on MPC8568E.

To solve this problem efficiently, QEIC needs pluggable handlers,
specific to the underlaying interrupt controller.

Patch extends qe_ic_init() function to accept low and high interrupt
handlers. To avoid #ifdefs, stack of interrupt handlers specified in
the header file and functions are marked 'static inline', thus
handlers are compiled-in only if actually used (in the board file).
Another option would be to lookup for parent controller and
automatically detect handlers (will waste text size because of
never used handlers, so this option abolished).

qe_ic_init() also changed in regard to support multiplexed high/low
lines as found in MPC8568E-MDS, plus qe_ic_cascade_muxed_mpic()
handler implemented appropriately.

Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Acked-by: Benjamin Herrenschmidt <benh@kernel.crashing.org>
Signed-off-by: Kumar Gala <galak@kernel.crashing.org>
arch/powerpc/platforms/83xx/mpc832x_mds.c
arch/powerpc/platforms/83xx/mpc832x_rdb.c
arch/powerpc/platforms/83xx/mpc836x_mds.c
arch/powerpc/platforms/85xx/mpc85xx_mds.c
arch/powerpc/sysdev/qe_lib/qe_ic.c
include/asm-powerpc/qe_ic.h

index b8d8c914569bef720625cffc1000e01ccbc1f692..972fa8528a8c606614767ec12f2539c8c001cad6 100644 (file)
@@ -140,7 +140,7 @@ static void __init mpc832x_sys_init_IRQ(void)
        if (!np)
                return;
 
-       qe_ic_init(np, 0);
+       qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
        of_node_put(np);
 #endif                         /* CONFIG_QUICC_ENGINE */
 }
index 4da0698487c04b443c55bcd9b0f609d39885509b..fbca336aa0ae8466f0b94cd0c96adf57bca636f3 100644 (file)
@@ -151,7 +151,7 @@ void __init mpc832x_rdb_init_IRQ(void)
        if (!np)
                return;
 
-       qe_ic_init(np, 0);
+       qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
        of_node_put(np);
 #endif                         /* CONFIG_QUICC_ENGINE */
 }
index 0b18a75e92008b1d3bf627e7169f7adcd158580c..0f3855c95ff5c6c0a4bc5d1caf78bfb2d6561be0 100644 (file)
@@ -147,7 +147,7 @@ static void __init mpc836x_mds_init_IRQ(void)
        if (!np)
                return;
 
-       qe_ic_init(np, 0);
+       qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
        of_node_put(np);
 #endif                         /* CONFIG_QUICC_ENGINE */
 }
index 00f4c3aef78bbaef52bd3a838a5cdfc5a9b08eff..57e840a1c027599bb8a13a68b17d3bb83cc93cc7 100644 (file)
@@ -180,7 +180,7 @@ static void __init mpc85xx_mds_pic_init(void)
        if (!np)
                return;
 
-       qe_ic_init(np, 0);
+       qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
        of_node_put(np);
 #endif                         /* CONFIG_QUICC_ENGINE */
 }
index 9a2d1edd050e2a32d9fedc5211075709170cc4a4..e1c0fd6dbc1aaf23400cc385d946602de5831d2d 100644 (file)
@@ -321,25 +321,9 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
        return irq_linear_revmap(qe_ic->irqhost, irq);
 }
 
-void qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc)
-{
-       struct qe_ic *qe_ic = desc->handler_data;
-       unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
-
-       if (cascade_irq != NO_IRQ)
-               generic_handle_irq(cascade_irq);
-}
-
-void qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
-{
-       struct qe_ic *qe_ic = desc->handler_data;
-       unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
-
-       if (cascade_irq != NO_IRQ)
-               generic_handle_irq(cascade_irq);
-}
-
-void __init qe_ic_init(struct device_node *node, unsigned int flags)
+void __init qe_ic_init(struct device_node *node, unsigned int flags,
+               void (*low_handler)(unsigned int irq, struct irq_desc *desc),
+               void (*high_handler)(unsigned int irq, struct irq_desc *desc))
 {
        struct qe_ic *qe_ic;
        struct resource res;
@@ -399,11 +383,12 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags)
        qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
 
        set_irq_data(qe_ic->virq_low, qe_ic);
-       set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low);
+       set_irq_chained_handler(qe_ic->virq_low, low_handler);
 
-       if (qe_ic->virq_high != NO_IRQ) {
+       if (qe_ic->virq_high != NO_IRQ &&
+                       qe_ic->virq_high != qe_ic->virq_low) {
                set_irq_data(qe_ic->virq_high, qe_ic);
-               set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high);
+               set_irq_chained_handler(qe_ic->virq_high, high_handler);
        }
 }
 
index e386fb7e44b0d928b3829f851fdd43b4ffda0a20..a779b2c9eaf163eb73c0f80faaedd24a1ea7e30f 100644 (file)
@@ -56,9 +56,75 @@ enum qe_ic_grp_id {
        QE_IC_GRP_RISCB         /* QE interrupt controller RISC group B */
 };
 
-void qe_ic_init(struct device_node *node, unsigned int flags);
+void qe_ic_init(struct device_node *node, unsigned int flags,
+               void (*low_handler)(unsigned int irq, struct irq_desc *desc),
+               void (*high_handler)(unsigned int irq, struct irq_desc *desc));
 void qe_ic_set_highest_priority(unsigned int virq, int high);
 int qe_ic_set_priority(unsigned int virq, unsigned int priority);
 int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
 
+struct qe_ic;
+unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic);
+unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic);
+
+static inline void qe_ic_cascade_low_ipic(unsigned int irq,
+                                         struct irq_desc *desc)
+{
+       struct qe_ic *qe_ic = desc->handler_data;
+       unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+}
+
+static inline void qe_ic_cascade_high_ipic(unsigned int irq,
+                                          struct irq_desc *desc)
+{
+       struct qe_ic *qe_ic = desc->handler_data;
+       unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+}
+
+static inline void qe_ic_cascade_low_mpic(unsigned int irq,
+                                         struct irq_desc *desc)
+{
+       struct qe_ic *qe_ic = desc->handler_data;
+       unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       desc->chip->eoi(irq);
+}
+
+static inline void qe_ic_cascade_high_mpic(unsigned int irq,
+                                          struct irq_desc *desc)
+{
+       struct qe_ic *qe_ic = desc->handler_data;
+       unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       desc->chip->eoi(irq);
+}
+
+static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
+                                           struct irq_desc *desc)
+{
+       struct qe_ic *qe_ic = desc->handler_data;
+       unsigned int cascade_irq;
+
+       cascade_irq = qe_ic_get_high_irq(qe_ic);
+       if (cascade_irq == NO_IRQ)
+               cascade_irq = qe_ic_get_low_irq(qe_ic);
+
+       if (cascade_irq != NO_IRQ)
+               generic_handle_irq(cascade_irq);
+
+       desc->chip->eoi(irq);
+}
+
 #endif /* _ASM_POWERPC_QE_IC_H */