diff options
author | Linus Walleij <linus.walleij@linaro.org> | 2020-04-28 13:38:47 +0200 |
---|---|---|
committer | Linus Walleij <linus.walleij@linaro.org> | 2020-04-28 13:38:47 +0200 |
commit | 8312d50b3f94f9cd634c7ce6e7a795b73925fe2f (patch) | |
tree | 4d5fc17f31d6c8e1906f7534260169a8936e8354 /drivers/gpio | |
parent | ae83d0b416db002fe95601e7f97f64b59514d936 (diff) | |
parent | 6409d049ce28bef35e13dfb8699fc7ee27469ba1 (diff) | |
download | lwn-8312d50b3f94f9cd634c7ce6e7a795b73925fe2f.tar.gz lwn-8312d50b3f94f9cd634c7ce6e7a795b73925fe2f.zip |
Merge tag 'gpio-fixes-for-v5.7-rc3' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux into fixes
gpio fixes for v5.7-rc3
- fix set_config in pca953x
- improve robustness of the new line watch/unwatch ioctl()
- fix a bug with caling a sleeping function with spinlock taken
Diffstat (limited to 'drivers/gpio')
-rw-r--r-- | drivers/gpio/gpio-pca953x.c | 2 | ||||
-rw-r--r-- | drivers/gpio/gpiolib.c | 29 |
2 files changed, 27 insertions, 4 deletions
diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index 5638b4e5355f..4269ea9a817e 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -531,7 +531,7 @@ static int pca953x_gpio_set_config(struct gpio_chip *gc, unsigned int offset, { struct pca953x_chip *chip = gpiochip_get_data(gc); - switch (config) { + switch (pinconf_to_config_param(config)) { case PIN_CONFIG_BIAS_PULL_UP: case PIN_CONFIG_BIAS_PULL_DOWN: return pca953x_gpio_set_pull_up_down(chip, offset, config); diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 40f2d7f69be2..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; @@ -1227,6 +1238,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) void __user *ip = (void __user *)arg; struct gpio_desc *desc; __u32 offset; + int hwgpio; /* We fail any subsequent ioctl():s when the chip is gone */ if (!gc) @@ -1259,13 +1271,19 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); + hwgpio = gpio_chip_hwgpio(desc); + + if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL && + test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + gpio_desc_to_lineinfo(desc, &lineinfo); if (copy_to_user(ip, &lineinfo, sizeof(lineinfo))) return -EFAULT; if (cmd == GPIO_GET_LINEINFO_WATCH_IOCTL) - set_bit(gpio_chip_hwgpio(desc), priv->watched_lines); + set_bit(hwgpio, priv->watched_lines); return 0; } else if (cmd == GPIO_GET_LINEHANDLE_IOCTL) { @@ -1280,7 +1298,12 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) if (IS_ERR(desc)) return PTR_ERR(desc); - clear_bit(gpio_chip_hwgpio(desc), priv->watched_lines); + hwgpio = gpio_chip_hwgpio(desc); + + if (!test_bit(hwgpio, priv->watched_lines)) + return -EBUSY; + + clear_bit(hwgpio, priv->watched_lines); return 0; } return -EINVAL; |