aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/gpio/gpio-grgpio.c
diff options
context:
space:
mode:
authorAlexandre Courbot <acourbot@nvidia.com>2015-08-17 04:23:52 -0400
committerLinus Walleij <linus.walleij@linaro.org>2015-08-17 04:56:24 -0400
commit7fa25937542358bfa01ef5c5a1e9a00bd164c000 (patch)
treed4edc6026912b6b8ad9450aa84f26f06d4b23794 /drivers/gpio/gpio-grgpio.c
parentac49fbd1f9d437cca7234473850aef4165779383 (diff)
gpio/grgpio: fix deadlock in grgpio_irq_unmap()
As reported by Alexey Khoroshilov: grgpio_irq_unmap() code looks quite suspicious regarding usage of priv->bgc.lock spinlock. It locks the spinlock in line 310: spin_lock_irqsave(&priv->bgc.lock, flags); and then it can call grgpio_set_imask() in line 317: grgpio_set_imask(priv, i, 0); But grgpio_set_imask() unconditionally locks the spinlock by itself. Fix this by moving the spinlock acquisition outside of grgpio_set_imask(). Found by Linux Driver Verification project (linuxtesting.org). Reported-by: Alexey Khoroshilov <khoroshilov@ispras.ru> Signed-off-by: Alexandre Courbot <acourbot@nvidia.com> Cc: Alexey Khoroshilov <khoroshilov@ispras.ru> Cc: Andreas Larsson <andreas@gaisler.com> Signed-off-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio/gpio-grgpio.c')
-rw-r--r--drivers/gpio/gpio-grgpio.c15
1 files changed, 10 insertions, 5 deletions
diff --git a/drivers/gpio/gpio-grgpio.c b/drivers/gpio/gpio-grgpio.c
index 77053d61466e..801423fe8143 100644
--- a/drivers/gpio/gpio-grgpio.c
+++ b/drivers/gpio/gpio-grgpio.c
@@ -104,17 +104,12 @@ static void grgpio_set_imask(struct grgpio_priv *priv, unsigned int offset,
104{ 104{
105 struct bgpio_chip *bgc = &priv->bgc; 105 struct bgpio_chip *bgc = &priv->bgc;
106 unsigned long mask = bgc->pin2mask(bgc, offset); 106 unsigned long mask = bgc->pin2mask(bgc, offset);
107 unsigned long flags;
108
109 spin_lock_irqsave(&bgc->lock, flags);
110 107
111 if (val) 108 if (val)
112 priv->imask |= mask; 109 priv->imask |= mask;
113 else 110 else
114 priv->imask &= ~mask; 111 priv->imask &= ~mask;
115 bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask); 112 bgc->write_reg(priv->regs + GRGPIO_IMASK, priv->imask);
116
117 spin_unlock_irqrestore(&bgc->lock, flags);
118} 113}
119 114
120static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset) 115static int grgpio_to_irq(struct gpio_chip *gc, unsigned offset)
@@ -180,16 +175,26 @@ static void grgpio_irq_mask(struct irq_data *d)
180{ 175{
181 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); 176 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
182 int offset = d->hwirq; 177 int offset = d->hwirq;
178 unsigned long flags;
179
180 spin_lock_irqsave(&priv->bgc.lock, flags);
183 181
184 grgpio_set_imask(priv, offset, 0); 182 grgpio_set_imask(priv, offset, 0);
183
184 spin_unlock_irqrestore(&priv->bgc.lock, flags);
185} 185}
186 186
187static void grgpio_irq_unmask(struct irq_data *d) 187static void grgpio_irq_unmask(struct irq_data *d)
188{ 188{
189 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d); 189 struct grgpio_priv *priv = irq_data_get_irq_chip_data(d);
190 int offset = d->hwirq; 190 int offset = d->hwirq;
191 unsigned long flags;
192
193 spin_lock_irqsave(&priv->bgc.lock, flags);
191 194
192 grgpio_set_imask(priv, offset, 1); 195 grgpio_set_imask(priv, offset, 1);
196
197 spin_unlock_irqrestore(&priv->bgc.lock, flags);
193} 198}
194 199
195static struct irq_chip grgpio_irq_chip = { 200static struct irq_chip grgpio_irq_chip = {