mirror of
https://git.kernel.org/pub/scm/linux/kernel/git/stable/linux.git
synced 2024-10-05 16:37:50 +00:00
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>
This commit is contained in:
parent
fcc152f3bf
commit
44f2c586a3
1 changed files with 26 additions and 8 deletions
|
@ -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,
|
||||||
|
|
Loading…
Reference in a new issue