summaryrefslogtreecommitdiffstats
path: root/drivers/gpio
diff options
context:
space:
mode:
authorBartosz Golaszewski <bgolaszewski@baylibre.com>2020-04-17 09:01:51 +0200
committerBartosz Golaszewski <bgolaszewski@baylibre.com>2020-04-23 17:55:27 +0200
commit6409d049ce28bef35e13dfb8699fc7ee27469ba1 (patch)
tree4d5fc17f31d6c8e1906f7534260169a8936e8354 /drivers/gpio
parent4e1541593017d76cfa04bd666de8e4dbcfe3105d (diff)
downloadlinux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.tar.gz
linux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.tar.bz2
linux-6409d049ce28bef35e13dfb8699fc7ee27469ba1.zip
gpiolib: don't call sleeping functions with a spinlock taken
We must not call pinctrl_gpio_can_use_line() with the gpio_lock taken as it takes a mutex internally. Let's move the call before taking the spinlock and store the return value. This isn't perfect - there's a moment between calling pinctrl_gpio_can_use_line() and taking the spinlock where the situation can change but it isn't a regression either: previously this part wasn't protected at all and it only affects the information user-space is seeing. Reported-by: Geert Uytterhoeven <geert@linux-m68k.org> Fixes: d2ac25798208 ("gpiolib: provide a dedicated function for setting lineinfo") Signed-off-by: Bartosz Golaszewski <bgolaszewski@baylibre.com> Acked-by: Linus Walleij <linus.walleij@linaro.org>
Diffstat (limited to 'drivers/gpio')
-rw-r--r--drivers/gpio/gpiolib.c13
1 files changed, 12 insertions, 1 deletions
diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c
index 29f6abe84d2e..bf9732ab7f91 100644
--- a/drivers/gpio/gpiolib.c
+++ b/drivers/gpio/gpiolib.c
@@ -1158,8 +1158,19 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
struct gpioline_info *info)
{
struct gpio_chip *gc = desc->gdev->chip;
+ bool ok_for_pinctrl;
unsigned long flags;
+ /*
+ * This function takes a mutex so we must check this before taking
+ * the spinlock.
+ *
+ * FIXME: find a non-racy way to retrieve this information. Maybe a
+ * lock common to both frameworks?
+ */
+ ok_for_pinctrl =
+ pinctrl_gpio_can_use_line(gc->base + info->line_offset);
+
spin_lock_irqsave(&gpio_lock, flags);
if (desc->name) {
@@ -1186,7 +1197,7 @@ static void gpio_desc_to_lineinfo(struct gpio_desc *desc,
test_bit(FLAG_USED_AS_IRQ, &desc->flags) ||
test_bit(FLAG_EXPORT, &desc->flags) ||
test_bit(FLAG_SYSFS, &desc->flags) ||
- !pinctrl_gpio_can_use_line(gc->base + info->line_offset))
+ !ok_for_pinctrl)
info->flags |= GPIOLINE_FLAG_KERNEL;
if (test_bit(FLAG_IS_OUT, &desc->flags))
info->flags |= GPIOLINE_FLAG_IS_OUT;