aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2007-10-05 13:47:29 -0400
committerKumar Gala <galak@kernel.crashing.org>2007-10-08 09:38:57 -0400
commitcccd21027c17c27ad275093c22475354b4495814 (patch)
tree75bd9835a6cb7677ddcab7c5091d7ca4e370b345
parent55f9ed0f6a3af19b5b5cc633eced658723bd3395 (diff)
[POWERPC] QEIC: Implement pluggable handlers, fix MPIC cascading
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>
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_mds.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc832x_rdb.c2
-rw-r--r--arch/powerpc/platforms/83xx/mpc836x_mds.c2
-rw-r--r--arch/powerpc/platforms/85xx/mpc85xx_mds.c2
-rw-r--r--arch/powerpc/sysdev/qe_lib/qe_ic.c29
-rw-r--r--include/asm-powerpc/qe_ic.h68
6 files changed, 78 insertions, 27 deletions
diff --git a/arch/powerpc/platforms/83xx/mpc832x_mds.c b/arch/powerpc/platforms/83xx/mpc832x_mds.c
index b8d8c914569b..972fa8528a8c 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_mds.c
@@ -140,7 +140,7 @@ static void __init mpc832x_sys_init_IRQ(void)
140 if (!np) 140 if (!np)
141 return; 141 return;
142 142
143 qe_ic_init(np, 0); 143 qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
144 of_node_put(np); 144 of_node_put(np);
145#endif /* CONFIG_QUICC_ENGINE */ 145#endif /* CONFIG_QUICC_ENGINE */
146} 146}
diff --git a/arch/powerpc/platforms/83xx/mpc832x_rdb.c b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
index 4da0698487c0..fbca336aa0ae 100644
--- a/arch/powerpc/platforms/83xx/mpc832x_rdb.c
+++ b/arch/powerpc/platforms/83xx/mpc832x_rdb.c
@@ -151,7 +151,7 @@ void __init mpc832x_rdb_init_IRQ(void)
151 if (!np) 151 if (!np)
152 return; 152 return;
153 153
154 qe_ic_init(np, 0); 154 qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
155 of_node_put(np); 155 of_node_put(np);
156#endif /* CONFIG_QUICC_ENGINE */ 156#endif /* CONFIG_QUICC_ENGINE */
157} 157}
diff --git a/arch/powerpc/platforms/83xx/mpc836x_mds.c b/arch/powerpc/platforms/83xx/mpc836x_mds.c
index 0b18a75e9200..0f3855c95ff5 100644
--- a/arch/powerpc/platforms/83xx/mpc836x_mds.c
+++ b/arch/powerpc/platforms/83xx/mpc836x_mds.c
@@ -147,7 +147,7 @@ static void __init mpc836x_mds_init_IRQ(void)
147 if (!np) 147 if (!np)
148 return; 148 return;
149 149
150 qe_ic_init(np, 0); 150 qe_ic_init(np, 0, qe_ic_cascade_low_ipic, qe_ic_cascade_high_ipic);
151 of_node_put(np); 151 of_node_put(np);
152#endif /* CONFIG_QUICC_ENGINE */ 152#endif /* CONFIG_QUICC_ENGINE */
153} 153}
diff --git a/arch/powerpc/platforms/85xx/mpc85xx_mds.c b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
index 00f4c3aef78b..57e840a1c027 100644
--- a/arch/powerpc/platforms/85xx/mpc85xx_mds.c
+++ b/arch/powerpc/platforms/85xx/mpc85xx_mds.c
@@ -180,7 +180,7 @@ static void __init mpc85xx_mds_pic_init(void)
180 if (!np) 180 if (!np)
181 return; 181 return;
182 182
183 qe_ic_init(np, 0); 183 qe_ic_init(np, 0, qe_ic_cascade_muxed_mpic, NULL);
184 of_node_put(np); 184 of_node_put(np);
185#endif /* CONFIG_QUICC_ENGINE */ 185#endif /* CONFIG_QUICC_ENGINE */
186} 186}
diff --git a/arch/powerpc/sysdev/qe_lib/qe_ic.c b/arch/powerpc/sysdev/qe_lib/qe_ic.c
index 9a2d1edd050e..e1c0fd6dbc1a 100644
--- a/arch/powerpc/sysdev/qe_lib/qe_ic.c
+++ b/arch/powerpc/sysdev/qe_lib/qe_ic.c
@@ -321,25 +321,9 @@ unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic)
321 return irq_linear_revmap(qe_ic->irqhost, irq); 321 return irq_linear_revmap(qe_ic->irqhost, irq);
322} 322}
323 323
324void qe_ic_cascade_low(unsigned int irq, struct irq_desc *desc) 324void __init qe_ic_init(struct device_node *node, unsigned int flags,
325{ 325 void (*low_handler)(unsigned int irq, struct irq_desc *desc),
326 struct qe_ic *qe_ic = desc->handler_data; 326 void (*high_handler)(unsigned int irq, struct irq_desc *desc))
327 unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
328
329 if (cascade_irq != NO_IRQ)
330 generic_handle_irq(cascade_irq);
331}
332
333void qe_ic_cascade_high(unsigned int irq, struct irq_desc *desc)
334{
335 struct qe_ic *qe_ic = desc->handler_data;
336 unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
337
338 if (cascade_irq != NO_IRQ)
339 generic_handle_irq(cascade_irq);
340}
341
342void __init qe_ic_init(struct device_node *node, unsigned int flags)
343{ 327{
344 struct qe_ic *qe_ic; 328 struct qe_ic *qe_ic;
345 struct resource res; 329 struct resource res;
@@ -399,11 +383,12 @@ void __init qe_ic_init(struct device_node *node, unsigned int flags)
399 qe_ic_write(qe_ic->regs, QEIC_CICR, temp); 383 qe_ic_write(qe_ic->regs, QEIC_CICR, temp);
400 384
401 set_irq_data(qe_ic->virq_low, qe_ic); 385 set_irq_data(qe_ic->virq_low, qe_ic);
402 set_irq_chained_handler(qe_ic->virq_low, qe_ic_cascade_low); 386 set_irq_chained_handler(qe_ic->virq_low, low_handler);
403 387
404 if (qe_ic->virq_high != NO_IRQ) { 388 if (qe_ic->virq_high != NO_IRQ &&
389 qe_ic->virq_high != qe_ic->virq_low) {
405 set_irq_data(qe_ic->virq_high, qe_ic); 390 set_irq_data(qe_ic->virq_high, qe_ic);
406 set_irq_chained_handler(qe_ic->virq_high, qe_ic_cascade_high); 391 set_irq_chained_handler(qe_ic->virq_high, high_handler);
407 } 392 }
408} 393}
409 394
diff --git a/include/asm-powerpc/qe_ic.h b/include/asm-powerpc/qe_ic.h
index e386fb7e44b0..a779b2c9eaf1 100644
--- a/include/asm-powerpc/qe_ic.h
+++ b/include/asm-powerpc/qe_ic.h
@@ -56,9 +56,75 @@ enum qe_ic_grp_id {
56 QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */ 56 QE_IC_GRP_RISCB /* QE interrupt controller RISC group B */
57}; 57};
58 58
59void qe_ic_init(struct device_node *node, unsigned int flags); 59void qe_ic_init(struct device_node *node, unsigned int flags,
60 void (*low_handler)(unsigned int irq, struct irq_desc *desc),
61 void (*high_handler)(unsigned int irq, struct irq_desc *desc));
60void qe_ic_set_highest_priority(unsigned int virq, int high); 62void qe_ic_set_highest_priority(unsigned int virq, int high);
61int qe_ic_set_priority(unsigned int virq, unsigned int priority); 63int qe_ic_set_priority(unsigned int virq, unsigned int priority);
62int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high); 64int qe_ic_set_high_priority(unsigned int virq, unsigned int priority, int high);
63 65
66struct qe_ic;
67unsigned int qe_ic_get_low_irq(struct qe_ic *qe_ic);
68unsigned int qe_ic_get_high_irq(struct qe_ic *qe_ic);
69
70static inline void qe_ic_cascade_low_ipic(unsigned int irq,
71 struct irq_desc *desc)
72{
73 struct qe_ic *qe_ic = desc->handler_data;
74 unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
75
76 if (cascade_irq != NO_IRQ)
77 generic_handle_irq(cascade_irq);
78}
79
80static inline void qe_ic_cascade_high_ipic(unsigned int irq,
81 struct irq_desc *desc)
82{
83 struct qe_ic *qe_ic = desc->handler_data;
84 unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
85
86 if (cascade_irq != NO_IRQ)
87 generic_handle_irq(cascade_irq);
88}
89
90static inline void qe_ic_cascade_low_mpic(unsigned int irq,
91 struct irq_desc *desc)
92{
93 struct qe_ic *qe_ic = desc->handler_data;
94 unsigned int cascade_irq = qe_ic_get_low_irq(qe_ic);
95
96 if (cascade_irq != NO_IRQ)
97 generic_handle_irq(cascade_irq);
98
99 desc->chip->eoi(irq);
100}
101
102static inline void qe_ic_cascade_high_mpic(unsigned int irq,
103 struct irq_desc *desc)
104{
105 struct qe_ic *qe_ic = desc->handler_data;
106 unsigned int cascade_irq = qe_ic_get_high_irq(qe_ic);
107
108 if (cascade_irq != NO_IRQ)
109 generic_handle_irq(cascade_irq);
110
111 desc->chip->eoi(irq);
112}
113
114static inline void qe_ic_cascade_muxed_mpic(unsigned int irq,
115 struct irq_desc *desc)
116{
117 struct qe_ic *qe_ic = desc->handler_data;
118 unsigned int cascade_irq;
119
120 cascade_irq = qe_ic_get_high_irq(qe_ic);
121 if (cascade_irq == NO_IRQ)
122 cascade_irq = qe_ic_get_low_irq(qe_ic);
123
124 if (cascade_irq != NO_IRQ)
125 generic_handle_irq(cascade_irq);
126
127 desc->chip->eoi(irq);
128}
129
64#endif /* _ASM_POWERPC_QE_IC_H */ 130#endif /* _ASM_POWERPC_QE_IC_H */