linux-mips
[Top] [All Lists]

[PATCH] MIPS: Alchemy: fix hang with high-frequency edge interrupts

To: Ralf Baechle <ralf@linux-mips.org>, Linux-MIPS <linux-mips@linux-mips.org>
Subject: [PATCH] MIPS: Alchemy: fix hang with high-frequency edge interrupts
From: Manuel Lauss <manuel.lauss@googlemail.com>
Date: Wed, 14 Oct 2009 12:22:20 +0200
Cc: Manuel Lauss <manuel.lauss@gmail.com>
Dkim-signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=googlemail.com; s=gamma; h=domainkey-signature:received:received:message-id:date:from :organization:user-agent:mime-version:to:cc:subject:content-type :content-transfer-encoding; bh=yaXZkIPk++rQONqOjH07CE/jfy4ZSTiGZCk/nIZQ/DA=; b=XngL4te//kcBjblzdTwY9AIJVJkpFZ03jb2f8nQAhngEEHjZSmqIEnsSXZTlcyPKvD HKnz/clEevtR4WBFuX3cNboLfdC27Av6bBTi/YMn5fIQ3VFtNXObHfV0a8peNwnG7WF9 U3czUnh3kGhMq4M1PrC6IqV8XQUfQ323aPLMk=
Domainkey-signature: a=rsa-sha1; c=nofws; d=googlemail.com; s=gamma; h=message-id:date:from:organization:user-agent:mime-version:to:cc :subject:content-type:content-transfer-encoding; b=Den8Y2dmS2ORdrTO7MUAs8vP7MuonNYpCY2Nh4i4fMCSMpdvKWOtkXSxXPUtfcZChG xytAocbECzCF+sPyjaGB3Op24pwEM+qI/LiKpEuPebu+ZIjmAf1J6LlxwuFPGvlVdEWX ylMkQGt2cAJiEgvJyXkUeDMU/75iwPeX0UFxc=
Organization: Private
Original-recipient: rfc822;linux-mips@linux-mips.org
Sender: linux-mips-bounce@linux-mips.org
User-agent: Thunderbird 2.0.0.23 (X11/20090828)
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>
---
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(-)

diff --git a/arch/mips/alchemy/common/irq.c b/arch/mips/alchemy/common/irq.c
index c88c821..d670928 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)
        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,
-- 
1.6.5


<Prev in Thread] Current Thread [Next in Thread>