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

Commit d3b421cd authored by Sekhar Nori's avatar Sekhar Nori Committed by Thomas Gleixner
Browse files

irqchip/omap-intc: Add support for spurious irq handling



Under some conditions, irq sorting procedure used by INTC can go wrong
resulting in a spurious irq getting reported.

If this condition is not handled, it results in endless stream of:

    unexpected IRQ trap at vector 00

messages from ack_bad_irq()

Handle the spurious interrupt condition in omap-intc driver to prevent this.

Measurements using kernel function profiler on AM335x EVM running at 720MHz
show that after this patch omap_intc_handle_irq() takes about 37.4us against
34us before this patch.

Signed-off-by: default avatarSekhar Nori <nsekhar@ti.com>
Acked-by: default avatarTony Lindgren <tony@atomide.com>
Cc: John Ogness <john.ogness@linutronix.de>
Cc: Felipe Balbi <balbi@ti.com>
Cc: Jason Cooper <jason@lakedaemon.net>
Cc: Marc Zyngier <marc.zyngier@arm.com>
Link: http://lkml.kernel.org/r/9c78a6db02ac55f7af7371b417b6e414d2c3095b.1450188128.git.nsekhar@ti.com


Cc: stable@vger.kernel.org
Signed-off-by: default avatarThomas Gleixner <tglx@linutronix.de>
parent 1fd9a710
Loading
Loading
Loading
Loading
+26 −1
Original line number Original line Diff line number Diff line
@@ -47,6 +47,7 @@
#define INTC_ILR0		0x0100
#define INTC_ILR0		0x0100


#define ACTIVEIRQ_MASK		0x7f	/* omap2/3 active interrupt bits */
#define ACTIVEIRQ_MASK		0x7f	/* omap2/3 active interrupt bits */
#define SPURIOUSIRQ_MASK	(0x1ffffff << 7)
#define INTCPS_NR_ILR_REGS	128
#define INTCPS_NR_ILR_REGS	128
#define INTCPS_NR_MIR_REGS	4
#define INTCPS_NR_MIR_REGS	4


@@ -329,11 +330,35 @@ static int __init omap_init_irq(u32 base, struct device_node *node)
static asmlinkage void __exception_irq_entry
static asmlinkage void __exception_irq_entry
omap_intc_handle_irq(struct pt_regs *regs)
omap_intc_handle_irq(struct pt_regs *regs)
{
{
	extern unsigned long irq_err_count;
	u32 irqnr;
	u32 irqnr;


	irqnr = intc_readl(INTC_SIR);
	irqnr = intc_readl(INTC_SIR);

	/*
	 * A spurious IRQ can result if interrupt that triggered the
	 * sorting is no longer active during the sorting (10 INTC
	 * functional clock cycles after interrupt assertion). Or a
	 * change in interrupt mask affected the result during sorting
	 * time. There is no special handling required except ignoring
	 * the SIR register value just read and retrying.
	 * See section 6.2.5 of AM335x TRM Literature Number: SPRUH73K
	 *
	 * Many a times, a spurious interrupt situation has been fixed
	 * by adding a flush for the posted write acking the IRQ in
	 * the device driver. Typically, this is going be the device
	 * driver whose interrupt was handled just before the spurious
	 * IRQ occurred. Pay attention to those device drivers if you
	 * run into hitting the spurious IRQ condition below.
	 */
	if (unlikely((irqnr & SPURIOUSIRQ_MASK) == SPURIOUSIRQ_MASK)) {
		pr_err_once("%s: spurious irq!\n", __func__);
		irq_err_count++;
		omap_ack_irq(NULL);
		return;
	}

	irqnr &= ACTIVEIRQ_MASK;
	irqnr &= ACTIVEIRQ_MASK;
	WARN_ONCE(!irqnr, "Spurious IRQ ?\n");
	handle_domain_irq(domain, irqnr, regs);
	handle_domain_irq(domain, irqnr, regs);
}
}