aboutsummaryrefslogtreecommitdiffstats
path: root/arch/arm
diff options
context:
space:
mode:
authorMarc Zyngier <maz@misterjones.org>2008-10-15 07:54:05 -0400
committerRussell King <rmk+kernel@arm.linux.org.uk>2008-10-15 08:01:36 -0400
commita9ff8f6462635c8d9f8d64b7b10ddcea8404d77b (patch)
tree0264af3d9285b706a5d8399edf09ea34028183a5 /arch/arm
parentaf2010daf7538b1483280f7aefffe4bff67696c0 (diff)
[ARM] 5308/1: Fix Viper ISA IRQ handling
The ISA IRQ renumbering broke the Viper ISA code in interesting ways. It originally assumed that ISA interrupt were numbered in the order that is defined by the CPLD registers. Unfortunately, this is no longer the case. Furthermore, the viper_irq_handler() function being a chained IRQ handler, it must ACK the interrupt by itself, or the handler will be immediately reentered, with the expected damages. This fix was made possible thanks to the help of David Raeman, who provided debug information and tested each version of this patch. Tested-by: David Raeman <david.raeman@gmail.com> Signed-off-by: Marc Zyngier <maz@misterjones.org> Acked-by: Eric Miao <eric.miao@marvell.com> Signed-off-by: Russell King <rmk+kernel@arm.linux.org.uk>
Diffstat (limited to 'arch/arm')
-rw-r--r--arch/arm/mach-pxa/viper.c54
1 files changed, 43 insertions, 11 deletions
diff --git a/arch/arm/mach-pxa/viper.c b/arch/arm/mach-pxa/viper.c
index d7632f63603c..4b3120dbc049 100644
--- a/arch/arm/mach-pxa/viper.c
+++ b/arch/arm/mach-pxa/viper.c
@@ -204,25 +204,54 @@ static void viper_set_core_cpu_voltage(unsigned long khz, int force)
204 204
205/* Interrupt handling */ 205/* Interrupt handling */
206static unsigned long viper_irq_enabled_mask; 206static unsigned long viper_irq_enabled_mask;
207static const int viper_isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 };
208static const int viper_isa_irq_map[] = {
209 0, /* ISA irq #0, invalid */
210 0, /* ISA irq #1, invalid */
211 0, /* ISA irq #2, invalid */
212 1 << 0, /* ISA irq #3 */
213 1 << 1, /* ISA irq #4 */
214 1 << 2, /* ISA irq #5 */
215 1 << 3, /* ISA irq #6 */
216 1 << 4, /* ISA irq #7 */
217 0, /* ISA irq #8, invalid */
218 1 << 8, /* ISA irq #9 */
219 1 << 5, /* ISA irq #10 */
220 1 << 6, /* ISA irq #11 */
221 1 << 7, /* ISA irq #12 */
222 0, /* ISA irq #13, invalid */
223 1 << 9, /* ISA irq #14 */
224 1 << 10, /* ISA irq #15 */
225};
226
227static inline int viper_irq_to_bitmask(unsigned int irq)
228{
229 return viper_isa_irq_map[irq - PXA_ISA_IRQ(0)];
230}
231
232static inline int viper_bit_to_irq(int bit)
233{
234 return viper_isa_irqs[bit] + PXA_ISA_IRQ(0);
235}
207 236
208static void viper_ack_irq(unsigned int irq) 237static void viper_ack_irq(unsigned int irq)
209{ 238{
210 int viper_irq = irq - PXA_ISA_IRQ(0); 239 int viper_irq = viper_irq_to_bitmask(irq);
211 240
212 if (viper_irq < 8) 241 if (viper_irq & 0xff)
213 VIPER_LO_IRQ_STATUS = 1 << viper_irq; 242 VIPER_LO_IRQ_STATUS = viper_irq;
214 else 243 else
215 VIPER_HI_IRQ_STATUS = 1 << (viper_irq - 8); 244 VIPER_HI_IRQ_STATUS = (viper_irq >> 8);
216} 245}
217 246
218static void viper_mask_irq(unsigned int irq) 247static void viper_mask_irq(unsigned int irq)
219{ 248{
220 viper_irq_enabled_mask &= ~(1 << (irq - PXA_ISA_IRQ(0))); 249 viper_irq_enabled_mask &= ~(viper_irq_to_bitmask(irq));
221} 250}
222 251
223static void viper_unmask_irq(unsigned int irq) 252static void viper_unmask_irq(unsigned int irq)
224{ 253{
225 viper_irq_enabled_mask |= (1 << (irq - PXA_ISA_IRQ(0))); 254 viper_irq_enabled_mask |= viper_irq_to_bitmask(irq);
226} 255}
227 256
228static inline unsigned long viper_irq_pending(void) 257static inline unsigned long viper_irq_pending(void)
@@ -237,8 +266,12 @@ static void viper_irq_handler(unsigned int irq, struct irq_desc *desc)
237 266
238 pending = viper_irq_pending(); 267 pending = viper_irq_pending();
239 do { 268 do {
269 /* we're in a chained irq handler,
270 * so ack the interrupt by hand */
271 GEDR(VIPER_CPLD_GPIO) = GPIO_bit(VIPER_CPLD_GPIO);
272
240 if (likely(pending)) { 273 if (likely(pending)) {
241 irq = PXA_ISA_IRQ(0) + __ffs(pending); 274 irq = viper_bit_to_irq(__ffs(pending));
242 generic_handle_irq(irq); 275 generic_handle_irq(irq);
243 } 276 }
244 pending = viper_irq_pending(); 277 pending = viper_irq_pending();
@@ -254,15 +287,14 @@ static struct irq_chip viper_irq_chip = {
254 287
255static void __init viper_init_irq(void) 288static void __init viper_init_irq(void)
256{ 289{
257 const int isa_irqs[] = { 3, 4, 5, 6, 7, 10, 11, 12, 9, 14, 15 }; 290 int level;
258 int irq;
259 int isa_irq; 291 int isa_irq;
260 292
261 pxa25x_init_irq(); 293 pxa25x_init_irq();
262 294
263 /* setup ISA IRQs */ 295 /* setup ISA IRQs */
264 for (irq = 0; irq < ARRAY_SIZE(isa_irqs); irq++) { 296 for (level = 0; level < ARRAY_SIZE(viper_isa_irqs); level++) {
265 isa_irq = isa_irqs[irq]; 297 isa_irq = viper_bit_to_irq(level);
266 set_irq_chip(isa_irq, &viper_irq_chip); 298 set_irq_chip(isa_irq, &viper_irq_chip);
267 set_irq_handler(isa_irq, handle_edge_irq); 299 set_irq_handler(isa_irq, handle_edge_irq);
268 set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE); 300 set_irq_flags(isa_irq, IRQF_VALID | IRQF_PROBE);