[PATCH PREEMPT_RT]: On AT91 ARM: GPIO Interrupt handling can/will stall forever

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Hello,

I use 2.6.23.1-rt5 on the Atmel AT91 series.
Interrupt threading on Preempt-RT and ARM works fine, except for
(edge-triggered) GPIO interrupts. There is a problem when a new
interrupt arives while the interrupt thread is handling the previous
interrupt. If this occurs the interrupt handling stalls forever.

This is caused by a unbalanced interrupt mask/unmask problem in the kernel.
The attached patch fixes this. More information about this problem is
documented inside the patch itself.

This patch is meant for Preempt-RT only.

Kind Regards,

Remy Bohmer
On ARM there is a problem where the interrupt handler stalls when they are 
coming faster than the kernel can handle.

The problem occurs when the routine handle_simple_irq() masks the interrupt 
when an IRQ-thread is handling the interrupt at the same time. (IRQ_INPROGRESS
is set). The interrupt thread, however does **never** a 
desc->chip->unmask(), so the interrupt becomes disabled forever.

IRQ_DISABLED is usually not set for this interrupt

This is in kernel/irq/chip.c, where the irq is masked when a IRQ-thread is
running: 
--------------------------------------------------------------------------
void fastcall
handle_simple_irq(unsigned int irq, struct irq_desc *desc)
{

....
....

	if (unlikely(!action || (desc->status & (IRQ_INPROGRESS |
						 IRQ_DISABLED)))) {
(!!)->		if (desc->chip->mask)
(!!)->			desc->chip->mask(irq);
		desc->status &= ~(IRQ_REPLAY | IRQ_WAITING);
		desc->status |= IRQ_PENDING;
		goto out_unlock;
	}

....
....
}
--------------------------------------------------------------------------

Masking the interrupt seems valid, because the interrupt handler thread is 
still running, so it can handle the new pending interrupt. But, it has to be
umasked somewhere. The logical place is to do this in kernel/irq/manage.c, 
because this situation is also handled for the thread_level_irq() and 
thread_fasteoi_irq(), but not for thread_simple_irq(). This patch adds this
for these kind of interrupts also.

Signed-off-by: Remy Bohmer <[email protected]>
---
 kernel/irq/manage.c |    3 +++
 1 file changed, 3 insertions(+)

Index: linux-2.6.23/kernel/irq/manage.c
===================================================================
--- linux-2.6.23.orig/kernel/irq/manage.c	2007-11-26 13:46:58.000000000 +0100
+++ linux-2.6.23/kernel/irq/manage.c	2007-11-26 13:48:30.000000000 +0100
@@ -646,6 +646,9 @@ static void thread_simple_irq(irq_desc_t
 			note_interrupt(irq, desc, action_ret);
 	}
 	desc->status &= ~IRQ_INPROGRESS;
+
+	if (!(desc->status & IRQ_DISABLED) && desc->chip->unmask)
+		desc->chip->unmask(irq);
 }
 
 /*

[Index of Archives]     [Kernel Newbies]     [Netfilter]     [Bugtraq]     [Photo]     [Stuff]     [Gimp]     [Yosemite News]     [MIPS Linux]     [ARM Linux]     [Linux Security]     [Linux RAID]     [Video 4 Linux]     [Linux for the blind]     [Linux Resources]
  Powered by Linux