MIPS: Alchemy: fix hang with high-frequency edge interrupts
PATCH 1/1 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.
---
Can be easily triggered with a simple not-debounced switch attached to an edge-triggered gpio.
arch/mips/alchemy/common/irq.c | 34 ++++++++++++++++++++++++++-------- 1 files changed, 26 insertions(+), 8 deletions(-)
arch/mips/alchemy/common/irq.c +26 -8
@@ -354,6 +354,28 @@ static void au1x_ic1_ack(unsigned int irq_nr)au_sync (); } +static void au1x_ic0_maskack (unsigned int irq_nr) +{ +unsigned int bit = irq_nr -AU1000_INTC0_INT_BASE ; + +au_writel (1 << bit,IC0_WAKECLR ); +au_writel (1 << bit,IC0_MASKCLR ); +au_writel (1 << bit,IC0_RISINGCLR ); +au_writel (1 << bit,IC0_FALLINGCLR ); +au_sync (); +} + +static void au1x_ic1_maskack (unsigned int irq_nr) +{ +unsigned int bit = irq_nr -AU1000_INTC1_INT_BASE ; + +au_writel (1 << bit,IC1_WAKECLR ); +au_writel (1 << bit,IC1_MASKCLR ); +au_writel (1 << bit,IC1_RISINGCLR ); +au_writel (1 << bit,IC1_FALLINGCLR ); +au_sync (); +} +static int au1x_ic1_setwake (unsigned int irq,unsigned int on) {unsigned int bit = irq -AU1000_INTC1_INT_BASE ;
@@ -379,25 +401,21 @@ static int au1x_ic1_setwake(unsigned int irq, unsigned int on)/* * irq_chips for both ICs; this way the mask handlers can be * as short as possible. -* -* NOTE: the ->ack() callback is used by the handle_edge_irq -* flowhandler only, the ->mask_ack() one by handle_level_irq, -* so no need for an irq_chip for each type of irq (level/edge). */ static struct irq_chip au1x_ic0_chip = { .name ="Alchemy-IC0" , - .ack = au1x_ic0_ack,/* edge */ + .ack = au1x_ic0_ack, .mask = au1x_ic0_mask, - .mask_ack = au1x_ic0_mask,/* level */ + .mask_ack = au1x_ic0_maskack, .unmask = au1x_ic0_unmask, .set_type = au1x_ic_settype, };static struct irq_chip au1x_ic1_chip = { .name ="Alchemy-IC1" , - .ack = au1x_ic1_ack,/* edge */ + .ack = au1x_ic1_ack, .mask = au1x_ic1_mask, - .mask_ack = au1x_ic1_mask,/* level */ + .mask_ack = au1x_ic1_maskack, .unmask = au1x_ic1_unmask, .set_type = au1x_ic_settype, .set_wake = au1x_ic1_setwake,
Signature · 1 line
1.6.5
Ralf Baechle
AppliedOn Wed, Oct 14, 2009 at 12:22:20PM +0200, Manuel Lauss wrote:
Thanks, applied.
Ralf