| From 43558d7569c38566e851c97962648c53ecc04bb9 Mon Sep 17 00:00:00 2001 |
| From: Remy Bohmer <linux@bohmer.net> |
| Date: Fri, 3 Jul 2009 08:44:15 -0500 |
| Subject: [PATCH] ARM: AT91: Use edge irq for AT91-GPIO |
| |
| commit a55fb4703922407dca8999eba8833512e6aba1ad in tip. |
| |
| 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 <linux@bohmer.net> |
| Signed-off-by: Ingo Molnar <mingo@elte.hu> |
| Signed-off-by: Thomas Gleixner <tglx@linutronix.de> |
| |
| diff --git a/arch/arm/mach-at91/gpio.c b/arch/arm/mach-at91/gpio.c |
| index ae4772e..d959979 100644 |
| --- a/arch/arm/mach-at91/gpio.c |
| +++ b/arch/arm/mach-at91/gpio.c |
| @@ -373,12 +373,18 @@ static int gpio_irq_type(unsigned pin, unsigned type) |
| } |
| } |
| |
| +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) |
| @@ -525,7 +531,7 @@ void __init at91_gpio_irq_setup(void) |
| * shorter, and the AIC handles interrupts 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); |
| } |
| |
| -- |
| 1.7.1.1 |
| |