[AT91: PATCH]: Use edge triggered interrupt handling for AT9…

Top Page
Attachments:
Message as email
+ (text/plain)
+ use-edge-triggered-irq-handler-instead-of-simple-irq.patch (text/x-patch)
Delete this message
Reply to this message
Author: Remy Bohmer
Date:  
To: linux
CC: Thomas Gleixner, Russell King - ARM Linux, ARM Linux Mailing List, Steven Rostedt
Subject: [AT91: PATCH]: Use edge triggered interrupt handling for AT91-GPIO instead of simple_irq-handler
Hello All,

On ARM there is a problem where the interrupt handler stalls when they are
coming faster than the kernel can handle.
The problem seems to occur on RT primarily, but the problem is also valid for
non-RT kernels.

The problem is twofold:
* the handle_simple_irq() mechanism is used for GPIO, but because the GPIO
interrupt source is actually an edge triggered interrupt source, the
handle_edge_irq() mechanism must be used. While using the simple_irq()
mechanisms edges can be missed for either mainline as RT kernels.
The simple_irq mechanism is *never* meant to be used for these types
of interrupts. SA1100 and PXA have exactly the same setup. They use the correct
handler. For more info: See the thread at: http://lkml.org/lkml/2007/11/26/73
* The RT kernels has a problem that the interrupt get masked forever while
the interrupt thread is running and a new interrupt arrives.
In the interrupt threads there is masking done in the handle_simple_irq()
path, while a simple_irq typically cannot be masked.

This patch only solves the first bullet, which is enough for AT91, by
moving the GPIO interrupt handler towards the handle_edge_irq().
To solve the problem in the simple_irq() path a seperate fix has to be done,
but as it is no longer used by AT91, that fix will not affect AT91.

Tested on:
* AT91rm9200-ek, and proprietary board
* AT91SAM9261-ek. (This patches also solves the problem that the
DM9000 does not work on this board while using PREEMPT-RT)

Patch Applied to 2.6.23.1

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 seems to occur on RT primarily, but the problem is also valid for
non-RT kernels.

The problem is twofold:
* the handle_simple_irq() mechanism is used for GPIO, but because the GPIO
interrupt source is actually an edge triggered interrupt source, the
handle_edge_irq() mechanism must be used. While using the simple_irq()
mechanisms edges can be missed for either mainline as RT kernels.
The simple_irq mechanism is *never* meant to be used for these types
of interrupts. See the thread at: http://lkml.org/lkml/2007/11/26/73
* The RT kernels has a problem that the interrupt get masked forever while
the interrupt thread is running and a new interrupt arrives.
In the interrupt threads there is masking done in the handle_simple_irq()
path, while a simple_irq typically cannot be masked.

This patch only solves the first bullet, which is enough for AT91, by
moving the GPIO interrupt handler towards the handle_edge_irq().
To solve the problem in the simple_irq() path a seperate fix has to be done,
but as it is no longer used by AT91, that fix will not affect AT91.

Tested on:
* AT91rm9200-ek, and proprietary board
* AT91SAM9261-ek. (This patches also solves the problem that the DM9000 does
                   not work on this board while using PREEMPT-RT)


Signed-off-by: Remy Bohmer <>
---
 arch/arm/mach-at91/gpio.c |    8 +++++++-
 1 file changed, 7 insertions(+), 1 deletion(-)


Index: linux-2.6.23/arch/arm/mach-at91/gpio.c
===================================================================
--- linux-2.6.23.orig/arch/arm/mach-at91/gpio.c    2007-11-29 15:33:13.000000000 +0100
+++ linux-2.6.23/arch/arm/mach-at91/gpio.c    2007-11-29 15:57:29.000000000 +0100
@@ -364,12 +364,18 @@ static int gpio_irq_type(unsigned pin, u
     return (type == IRQT_BOTHEDGE) ? 0 : -EINVAL;
 }


+static void gpio_irq_ack_noop(unsigned int irq)
+{
+    /* Dummy function.  */
+}
+
 static struct irq_chip gpio_irqchip = {
     .name        = "GPIO",
     .mask        = gpio_irq_mask,
     .unmask        = gpio_irq_unmask,
     .set_type    = gpio_irq_type,
     .set_wake    = gpio_irq_set_wake,
+    .ack            = gpio_irq_ack_noop,
 };


 static void gpio_irq_handler(unsigned irq, struct irq_desc *desc)
@@ -504,7 +510,7 @@ void __init at91_gpio_irq_setup(void)
              * shorter, and the AIC handles interupts sanely.
              */
             set_irq_chip(pin, &gpio_irqchip);
-            set_irq_handler(pin, handle_simple_irq);
+            set_irq_handler(pin, handle_edge_irq);
             set_irq_flags(pin, IRQF_VALID);
         }