aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorManuel Lauss <manuel.lauss@googlemail.com>2009-10-14 06:22:20 -0400
committerRalf Baechle <ralf@linux-mips.org>2009-11-02 06:00:08 -0500
commit44f2c586a3553154bc6549eb696c7716c85f910b (patch)
tree1050bd39b5fd1d67c63dddd939223b60ad7f9a44
parentfcc152f3bf55cec61167b173774cbf717b0ff5e4 (diff)
MIPS: Alchemy: Fix hang with high-frequency edge interrupts
The handle_edge_irq() flowhandler disables edge int sources which occur too fast (i.e. another edge comes in before the irq handler function had a chance to finish). Currently, the mask_ack() callback does not ack the edges in hardware, leading to an endless loop in the flowhandler where it tries to shut up the irq source. When I rewrote the alchemy IRQ code I wrongly assumed the mask_ack() callback was only used by the level flowhandler, hence it omitted the (at the time pointless) edge acks. Turned out I was wrong; so here is a complete mask_ack implementation for Alchemy IC, which fixes the above mentioned problem. Signed-off-by: Manuel Lauss <manuel.lauss@gmail.com> Signed-off-by: Ralf Baechle <ralf@linux-mips.org>
-rw-r--r--arch/mips/alchemy/common/irq.c34
1 files changed, 26 insertions, 8 deletions
diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c88c821b4c36..d670928afcfd 100644
--- a/arch/mips/alchemy/common/irq.c
+++ b/arch/mips/alchemy/common/irq.c
@@ -354,6 +354,28 @@ static void au1x_ic1_ack(unsigned int irq_nr)
354 au_sync(); 354 au_sync();
355} 355}
356 356
357static void au1x_ic0_maskack(unsigned int irq_nr)
358{
359 unsigned int bit = irq_nr - AU1000_INTC0_INT_BASE;
360
361 au_writel(1 << bit, IC0_WAKECLR);
362 au_writel(1 << bit, IC0_MASKCLR);
363 au_writel(1 << bit, IC0_RISINGCLR);
364 au_writel(1 << bit, IC0_FALLINGCLR);
365 au_sync();
366}
367
368static void au1x_ic1_maskack(unsigned int irq_nr)
369{
370 unsigned int bit = irq_nr - AU1000_INTC1_INT_BASE;
371
372 au_writel(1 << bit, IC1_WAKECLR);
373 au_writel(1 << bit, IC1_MASKCLR);
374 au_writel(1 << bit, IC1_RISINGCLR);
375 au_writel(1 << bit, IC1_FALLINGCLR);
376 au_sync();
377}
378
357static int au1x_ic1_setwake(unsigned int irq, unsigned int on) 379static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
358{ 380{
359 unsigned int bit = irq - AU1000_INTC1_INT_BASE; 381 unsigned int bit = irq - AU1000_INTC1_INT_BASE;
@@ -379,25 +401,21 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
379/* 401/*
380 * irq_chips for both ICs; this way the mask handlers can be 402 * irq_chips for both ICs; this way the mask handlers can be
381 * as short as possible. 403 * as short as possible.
382 *
383 * NOTE: the ->ack() callback is used by the handle_edge_irq
384 * flowhandler only, the ->mask_ack() one by handle_level_irq,
385 * so no need for an irq_chip for each type of irq (level/edge).
386 */ 404 */
387static struct irq_chip au1x_ic0_chip = { 405static struct irq_chip au1x_ic0_chip = {
388 .name = "Alchemy-IC0", 406 .name = "Alchemy-IC0",
389 .ack = au1x_ic0_ack, /* edge */ 407 .ack = au1x_ic0_ack,
390 .mask = au1x_ic0_mask, 408 .mask = au1x_ic0_mask,
391 .mask_ack = au1x_ic0_mask, /* level */ 409 .mask_ack = au1x_ic0_maskack,
392 .unmask = au1x_ic0_unmask, 410 .unmask = au1x_ic0_unmask,
393 .set_type = au1x_ic_settype, 411 .set_type = au1x_ic_settype,
394}; 412};
395 413
396static struct irq_chip au1x_ic1_chip = { 414static struct irq_chip au1x_ic1_chip = {
397 .name = "Alchemy-IC1", 415 .name = "Alchemy-IC1",
398 .ack = au1x_ic1_ack, /* edge */ 416 .ack = au1x_ic1_ack,
399 .mask = au1x_ic1_mask, 417 .mask = au1x_ic1_mask,
400 .mask_ack = au1x_ic1_mask, /* level */ 418 .mask_ack = au1x_ic1_maskack,
401 .unmask = au1x_ic1_unmask, 419 .unmask = au1x_ic1_unmask,
402 .set_type = au1x_ic_settype, 420 .set_type = au1x_ic_settype,
403 .set_wake = au1x_ic1_setwake, 421 .set_wake = au1x_ic1_setwake,