Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 44f2c586 authored by Manuel Lauss's avatar Manuel Lauss Committed by Ralf Baechle
Browse files

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: default avatarManuel Lauss <manuel.lauss@gmail.com>
Signed-off-by: default avatarRalf Baechle <ralf@linux-mips.org>
parent fcc152f3
Loading
Loading
Loading
Loading
+26 −8
Original line number Original line Diff line number Diff line
@@ -354,6 +354,28 @@ static void au1x_ic1_ack(unsigned int irq_nr)
	au_sync();
	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)
static int au1x_ic1_setwake(unsigned int irq, unsigned int on)
{
{
	unsigned int bit = irq - AU1000_INTC1_INT_BASE;
	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
 * irq_chips for both ICs; this way the mask handlers can be
 * as short as possible.
 * 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 = {
static struct irq_chip au1x_ic0_chip = {
	.name		= "Alchemy-IC0",
	.name		= "Alchemy-IC0",
	.ack		= au1x_ic0_ack,		/* edge */
	.ack		= au1x_ic0_ack,
	.mask		= au1x_ic0_mask,
	.mask		= au1x_ic0_mask,
	.mask_ack	= au1x_ic0_mask,	/* level */
	.mask_ack	= au1x_ic0_maskack,
	.unmask		= au1x_ic0_unmask,
	.unmask		= au1x_ic0_unmask,
	.set_type	= au1x_ic_settype,
	.set_type	= au1x_ic_settype,
};
};


static struct irq_chip au1x_ic1_chip = {
static struct irq_chip au1x_ic1_chip = {
	.name		= "Alchemy-IC1",
	.name		= "Alchemy-IC1",
	.ack		= au1x_ic1_ack,		/* edge */
	.ack		= au1x_ic1_ack,
	.mask		= au1x_ic1_mask,
	.mask		= au1x_ic1_mask,
	.mask_ack	= au1x_ic1_mask,	/* level */
	.mask_ack	= au1x_ic1_maskack,
	.unmask		= au1x_ic1_unmask,
	.unmask		= au1x_ic1_unmask,
	.set_type	= au1x_ic_settype,
	.set_type	= au1x_ic_settype,
	.set_wake	= au1x_ic1_setwake,
	.set_wake	= au1x_ic1_setwake,