diff mbox series

gpio: timberdale: Fix potential deadlock on &tgpio->lock

Message ID 20230926102914.6145-1-dg573847474@gmail.com
State Accepted
Commit 9e8bc2dda5a7a8e2babc9975f4b11c9a6196e490
Headers show
Series gpio: timberdale: Fix potential deadlock on &tgpio->lock | expand

Commit Message

Chengfeng Ye Sept. 26, 2023, 10:29 a.m. UTC
As timbgpio_irq_enable()/timbgpio_irq_disable() callback could be
executed under irq context, it could introduce double locks on
&tgpio->lock if it preempts other execution units requiring
the same locks.

timbgpio_gpio_set()
--> timbgpio_update_bit()
--> spin_lock(&tgpio->lock)
<interrupt>
   --> timbgpio_irq_disable()
   --> spin_lock_irqsave(&tgpio->lock)

This flaw was found by an experimental static analysis tool I am
developing for irq-related deadlock.

To prevent the potential deadlock, the patch uses spin_lock_irqsave()
on &tgpio->lock inside timbgpio_gpio_set() to prevent the possible
deadlock scenario.

Signed-off-by: Chengfeng Ye <dg573847474@gmail.com>
---
 drivers/gpio/gpio-timberdale.c | 5 +++--
 1 file changed, 3 insertions(+), 2 deletions(-)

Comments

Andy Shevchenko Sept. 26, 2023, 12:58 p.m. UTC | #1
On Tue, Sep 26, 2023 at 10:29:14AM +0000, Chengfeng Ye wrote:
> As timbgpio_irq_enable()/timbgpio_irq_disable() callback could be
> executed under irq context, it could introduce double locks on
> &tgpio->lock if it preempts other execution units requiring
> the same locks.
> 
> timbgpio_gpio_set()
> --> timbgpio_update_bit()
> --> spin_lock(&tgpio->lock)
> <interrupt>
>    --> timbgpio_irq_disable()
>    --> spin_lock_irqsave(&tgpio->lock)
> 
> This flaw was found by an experimental static analysis tool I am
> developing for irq-related deadlock.
> 
> To prevent the potential deadlock, the patch uses spin_lock_irqsave()
> on &tgpio->lock inside timbgpio_gpio_set() to prevent the possible
> deadlock scenario.

Okay, makes sense.
Reviewed-by: Andy Shevchenko <andy@kernel.org>

Question to the users of this hardware if they ever want to have this IRQ chip
in the RT environment. In that case the locking type needs to be raw.
Bartosz Golaszewski Sept. 27, 2023, 6:52 a.m. UTC | #2
On Tue, Sep 26, 2023 at 12:29 PM Chengfeng Ye <dg573847474@gmail.com> wrote:
>
> As timbgpio_irq_enable()/timbgpio_irq_disable() callback could be
> executed under irq context, it could introduce double locks on
> &tgpio->lock if it preempts other execution units requiring
> the same locks.
>
> timbgpio_gpio_set()
> --> timbgpio_update_bit()
> --> spin_lock(&tgpio->lock)
> <interrupt>
>    --> timbgpio_irq_disable()
>    --> spin_lock_irqsave(&tgpio->lock)
>
> This flaw was found by an experimental static analysis tool I am
> developing for irq-related deadlock.
>
> To prevent the potential deadlock, the patch uses spin_lock_irqsave()
> on &tgpio->lock inside timbgpio_gpio_set() to prevent the possible
> deadlock scenario.
>
> Signed-off-by: Chengfeng Ye <dg573847474@gmail.com>
> ---
>  drivers/gpio/gpio-timberdale.c | 5 +++--
>  1 file changed, 3 insertions(+), 2 deletions(-)
>
> diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
> index bbd9e9191199..fad979797486 100644
> --- a/drivers/gpio/gpio-timberdale.c
> +++ b/drivers/gpio/gpio-timberdale.c
> @@ -43,9 +43,10 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
>         unsigned offset, bool enabled)
>  {
>         struct timbgpio *tgpio = gpiochip_get_data(gpio);
> +       unsigned long flags;
>         u32 reg;
>
> -       spin_lock(&tgpio->lock);
> +       spin_lock_irqsave(&tgpio->lock, flags);
>         reg = ioread32(tgpio->membase + offset);
>
>         if (enabled)
> @@ -54,7 +55,7 @@ static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
>                 reg &= ~(1 << index);
>
>         iowrite32(reg, tgpio->membase + offset);
> -       spin_unlock(&tgpio->lock);
> +       spin_unlock_irqrestore(&tgpio->lock, flags);
>
>         return 0;
>  }
> --
> 2.17.1
>

Applied, thanks!

Bart
diff mbox series

Patch

diff --git a/drivers/gpio/gpio-timberdale.c b/drivers/gpio/gpio-timberdale.c
index bbd9e9191199..fad979797486 100644
--- a/drivers/gpio/gpio-timberdale.c
+++ b/drivers/gpio/gpio-timberdale.c
@@ -43,9 +43,10 @@  static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
 	unsigned offset, bool enabled)
 {
 	struct timbgpio *tgpio = gpiochip_get_data(gpio);
+	unsigned long flags;
 	u32 reg;
 
-	spin_lock(&tgpio->lock);
+	spin_lock_irqsave(&tgpio->lock, flags);
 	reg = ioread32(tgpio->membase + offset);
 
 	if (enabled)
@@ -54,7 +55,7 @@  static int timbgpio_update_bit(struct gpio_chip *gpio, unsigned index,
 		reg &= ~(1 << index);
 
 	iowrite32(reg, tgpio->membase + offset);
-	spin_unlock(&tgpio->lock);
+	spin_unlock_irqrestore(&tgpio->lock, flags);
 
 	return 0;
 }