aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorGregory CLEMENT <gregory.clement@free-electrons.com>2015-04-02 11:11:11 -0400
committerLinus Walleij <linus.walleij@linaro.org>2015-04-08 10:35:07 -0400
commit61819549f572edd7fce53f228c0d8420cdc85f71 (patch)
tree236a81ed3d9cc0bf9998e9aac6215ac43f3be45f
parent177b0381c5e39180b237284231a02fa783a3af3b (diff)
gpio: mvebu: Fix mask/unmask managment per irq chip type
Level IRQ handlers and edge IRQ handler are managed by tow different sets of registers. But currently the driver uses the same mask for the both registers. It lead to issues with the following scenario: First, an IRQ is requested on a GPIO to be triggered on front. After, this an other IRQ is requested for a GPIO of the same bank but triggered on level. Then the first one will be also setup to be triggered on level. It leads to an interrupt storm. The different kind of handler are already associated with two different irq chip type. With this patch the driver uses a private mask for each one which solves this issue. It has been tested on an Armada XP based board and on an Armada 375 board. For the both boards, with this patch is applied, there is no such interrupt storm when running the previous scenario. This bug was already fixed but in a different way in the legacy version of this driver by Evgeniy Dushistov: 9ece8839b1277fb9128ff6833411614ab6c88d68 "ARM: orion: Fix for certain sequence of request_irq can cause irq storm". The fact the new version of the gpio drive could be affected had been discussed there: http://thread.gmane.org/gmane.linux.ports.arm.kernel/344670/focus=364012 Reported-by: Evgeniy A. Dushistov <dushistov@mail.ru> Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com> Cc: <stable@vger.kernel.org> # v3.7 + Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
-rw-r--r--drivers/gpio/gpio-mvebu.c24
1 files changed, 16 insertions, 8 deletions
diff --git a/drivers/gpio/gpio-mvebu.c b/drivers/gpio/gpio-mvebu.c
index d0bc123c7975..1a54205860f5 100644
--- a/drivers/gpio/gpio-mvebu.c
+++ b/drivers/gpio/gpio-mvebu.c
@@ -320,11 +320,13 @@ static void mvebu_gpio_edge_irq_mask(struct irq_data *d)
320{ 320{
321 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 321 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
322 struct mvebu_gpio_chip *mvchip = gc->private; 322 struct mvebu_gpio_chip *mvchip = gc->private;
323 struct irq_chip_type *ct = irq_data_get_chip_type(d);
323 u32 mask = 1 << (d->irq - gc->irq_base); 324 u32 mask = 1 << (d->irq - gc->irq_base);
324 325
325 irq_gc_lock(gc); 326 irq_gc_lock(gc);
326 gc->mask_cache &= ~mask; 327 ct->mask_cache_priv &= ~mask;
327 writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip)); 328
329 writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
328 irq_gc_unlock(gc); 330 irq_gc_unlock(gc);
329} 331}
330 332
@@ -332,11 +334,13 @@ static void mvebu_gpio_edge_irq_unmask(struct irq_data *d)
332{ 334{
333 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 335 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
334 struct mvebu_gpio_chip *mvchip = gc->private; 336 struct mvebu_gpio_chip *mvchip = gc->private;
337 struct irq_chip_type *ct = irq_data_get_chip_type(d);
338
335 u32 mask = 1 << (d->irq - gc->irq_base); 339 u32 mask = 1 << (d->irq - gc->irq_base);
336 340
337 irq_gc_lock(gc); 341 irq_gc_lock(gc);
338 gc->mask_cache |= mask; 342 ct->mask_cache_priv |= mask;
339 writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip)); 343 writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
340 irq_gc_unlock(gc); 344 irq_gc_unlock(gc);
341} 345}
342 346
@@ -344,11 +348,13 @@ static void mvebu_gpio_level_irq_mask(struct irq_data *d)
344{ 348{
345 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 349 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
346 struct mvebu_gpio_chip *mvchip = gc->private; 350 struct mvebu_gpio_chip *mvchip = gc->private;
351 struct irq_chip_type *ct = irq_data_get_chip_type(d);
352
347 u32 mask = 1 << (d->irq - gc->irq_base); 353 u32 mask = 1 << (d->irq - gc->irq_base);
348 354
349 irq_gc_lock(gc); 355 irq_gc_lock(gc);
350 gc->mask_cache &= ~mask; 356 ct->mask_cache_priv &= ~mask;
351 writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip)); 357 writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
352 irq_gc_unlock(gc); 358 irq_gc_unlock(gc);
353} 359}
354 360
@@ -356,11 +362,13 @@ static void mvebu_gpio_level_irq_unmask(struct irq_data *d)
356{ 362{
357 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d); 363 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
358 struct mvebu_gpio_chip *mvchip = gc->private; 364 struct mvebu_gpio_chip *mvchip = gc->private;
365 struct irq_chip_type *ct = irq_data_get_chip_type(d);
366
359 u32 mask = 1 << (d->irq - gc->irq_base); 367 u32 mask = 1 << (d->irq - gc->irq_base);
360 368
361 irq_gc_lock(gc); 369 irq_gc_lock(gc);
362 gc->mask_cache |= mask; 370 ct->mask_cache_priv |= mask;
363 writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip)); 371 writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
364 irq_gc_unlock(gc); 372 irq_gc_unlock(gc);
365} 373}
366 374