diff options
| author | Manuel Lauss <manuel.lauss@googlemail.com> | 2009-10-14 06:22:20 -0400 |
|---|---|---|
| committer | Ralf Baechle <ralf@linux-mips.org> | 2009-11-02 06:00:08 -0500 |
| commit | 44f2c586a3553154bc6549eb696c7716c85f910b (patch) | |
| tree | 1050bd39b5fd1d67c63dddd939223b60ad7f9a44 | |
| parent | fcc152f3bf55cec61167b173774cbf717b0ff5e4 (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.c | 34 |
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 | ||
| 357 | static 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 | |||
| 368 | static 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 | |||
| 357 | static int au1x_ic1_setwake(unsigned int irq, unsigned int on) | 379 | static 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 | */ |
| 387 | static struct irq_chip au1x_ic0_chip = { | 405 | static 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 | ||
| 396 | static struct irq_chip au1x_ic1_chip = { | 414 | static 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, |
