]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/blob - releases/3.19.7/gpio-mvebu-fix-mask-unmask-managment-per-irq-chip-type.patch
4.9-stable patches
[thirdparty/kernel/stable-queue.git] / releases / 3.19.7 / gpio-mvebu-fix-mask-unmask-managment-per-irq-chip-type.patch
1 From 61819549f572edd7fce53f228c0d8420cdc85f71 Mon Sep 17 00:00:00 2001
2 From: Gregory CLEMENT <gregory.clement@free-electrons.com>
3 Date: Thu, 2 Apr 2015 17:11:11 +0200
4 Subject: gpio: mvebu: Fix mask/unmask managment per irq chip type
5
6 From: Gregory CLEMENT <gregory.clement@free-electrons.com>
7
8 commit 61819549f572edd7fce53f228c0d8420cdc85f71 upstream.
9
10 Level IRQ handlers and edge IRQ handler are managed by tow different
11 sets of registers. But currently the driver uses the same mask for the
12 both registers. It lead to issues with the following scenario:
13
14 First, an IRQ is requested on a GPIO to be triggered on front. After,
15 this an other IRQ is requested for a GPIO of the same bank but
16 triggered on level. Then the first one will be also setup to be
17 triggered on level. It leads to an interrupt storm.
18
19 The different kind of handler are already associated with two
20 different irq chip type. With this patch the driver uses a private
21 mask for each one which solves this issue.
22
23 It has been tested on an Armada XP based board and on an Armada 375
24 board. For the both boards, with this patch is applied, there is no
25 such interrupt storm when running the previous scenario.
26
27 This bug was already fixed but in a different way in the legacy
28 version of this driver by Evgeniy Dushistov:
29 9ece8839b1277fb9128ff6833411614ab6c88d68 "ARM: orion: Fix for certain
30 sequence of request_irq can cause irq storm". The fact the new version
31 of the gpio drive could be affected had been discussed there:
32 http://thread.gmane.org/gmane.linux.ports.arm.kernel/344670/focus=364012
33
34 Reported-by: Evgeniy A. Dushistov <dushistov@mail.ru>
35 Signed-off-by: Gregory CLEMENT <gregory.clement@free-electrons.com>
36 Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
37 Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
38
39 ---
40 drivers/gpio/gpio-mvebu.c | 24 ++++++++++++++++--------
41 1 file changed, 16 insertions(+), 8 deletions(-)
42
43 --- a/drivers/gpio/gpio-mvebu.c
44 +++ b/drivers/gpio/gpio-mvebu.c
45 @@ -313,11 +313,13 @@ static void mvebu_gpio_edge_irq_mask(str
46 {
47 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
48 struct mvebu_gpio_chip *mvchip = gc->private;
49 + struct irq_chip_type *ct = irq_data_get_chip_type(d);
50 u32 mask = 1 << (d->irq - gc->irq_base);
51
52 irq_gc_lock(gc);
53 - gc->mask_cache &= ~mask;
54 - writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
55 + ct->mask_cache_priv &= ~mask;
56 +
57 + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
58 irq_gc_unlock(gc);
59 }
60
61 @@ -325,11 +327,13 @@ static void mvebu_gpio_edge_irq_unmask(s
62 {
63 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
64 struct mvebu_gpio_chip *mvchip = gc->private;
65 + struct irq_chip_type *ct = irq_data_get_chip_type(d);
66 +
67 u32 mask = 1 << (d->irq - gc->irq_base);
68
69 irq_gc_lock(gc);
70 - gc->mask_cache |= mask;
71 - writel_relaxed(gc->mask_cache, mvebu_gpioreg_edge_mask(mvchip));
72 + ct->mask_cache_priv |= mask;
73 + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_edge_mask(mvchip));
74 irq_gc_unlock(gc);
75 }
76
77 @@ -337,11 +341,13 @@ static void mvebu_gpio_level_irq_mask(st
78 {
79 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
80 struct mvebu_gpio_chip *mvchip = gc->private;
81 + struct irq_chip_type *ct = irq_data_get_chip_type(d);
82 +
83 u32 mask = 1 << (d->irq - gc->irq_base);
84
85 irq_gc_lock(gc);
86 - gc->mask_cache &= ~mask;
87 - writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
88 + ct->mask_cache_priv &= ~mask;
89 + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
90 irq_gc_unlock(gc);
91 }
92
93 @@ -349,11 +355,13 @@ static void mvebu_gpio_level_irq_unmask(
94 {
95 struct irq_chip_generic *gc = irq_data_get_irq_chip_data(d);
96 struct mvebu_gpio_chip *mvchip = gc->private;
97 + struct irq_chip_type *ct = irq_data_get_chip_type(d);
98 +
99 u32 mask = 1 << (d->irq - gc->irq_base);
100
101 irq_gc_lock(gc);
102 - gc->mask_cache |= mask;
103 - writel_relaxed(gc->mask_cache, mvebu_gpioreg_level_mask(mvchip));
104 + ct->mask_cache_priv |= mask;
105 + writel_relaxed(ct->mask_cache_priv, mvebu_gpioreg_level_mask(mvchip));
106 irq_gc_unlock(gc);
107 }
108