From 9c10280d85c14a20751ab6c1185ad725172936d6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Wed, 25 May 2016 10:56:03 +0200 Subject: gpio: flush direction status in gpiochip_lock_as_irq() As irqchip and gpiochip functions are orthogonal, the IRQ set-up or something else can have changed the direction of the GPIO line from what the GPIO descriptor knows when we get into gpiochip_lock_as_irq(). Make sure to re-read the direction setting if we have the .get_direction() callback enabled for the chip. Else we get problems like this: iio iio:device2: interrupts on the rising edge gpio gpiochip2: (8012e080.gpio): gpiochip_lock_as_irq: tried to flag a GPIO set as output for IRQ gpio gpiochip2: (8012e080.gpio): unable to lock HW IRQ 0 for IRQ genirq: Failed to request resources for l3g4200d-trigger (irq 111) on irqchip nmk1-32-63 iio iio:device2: failed to request trigger IRQ. st-gyro-i2c: probe of 2-0068 failed with error -22 Fixes: 72d320006177 ("gpio: set up initial state from .get_direction()") Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 21 +++++++++++++++++---- 1 file changed, 17 insertions(+), 4 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index d407f904a31c..e901d2666b46 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -2066,17 +2066,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); */ int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) { - if (offset >= chip->ngpio) - return -EINVAL; + struct gpio_desc *desc; + + desc = gpiochip_get_desc(chip, offset); + if (IS_ERR(desc)) + return PTR_ERR(desc); + + /* Flush direction if something changed behind our back */ + if (chip->get_direction) { + int dir = chip->get_direction(chip, offset); + + if (dir) + clear_bit(FLAG_IS_OUT, &desc->flags); + else + set_bit(FLAG_IS_OUT, &desc->flags); + } - if (test_bit(FLAG_IS_OUT, &chip->gpiodev->descs[offset].flags)) { + if (test_bit(FLAG_IS_OUT, &desc->flags)) { chip_err(chip, "%s: tried to flag a GPIO set as output for IRQ\n", __func__); return -EIO; } - set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); + set_bit(FLAG_USED_AS_IRQ, &desc->flags); return 0; } EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); -- cgit v1.2.3 From 8b92e17efe029cc19f435f9fcbdfb1e7b9beb0ef Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Fri, 27 May 2016 14:24:04 +0200 Subject: gpio: handle compatible ioctl() pointers If we're using the compatible ioctl() we need to handle the argument pointer in a special way or there will be trouble. Fixes: 3c702e9987e2 ("gpio: add a userspace chardev ABI for GPIOs") Reported-by: Dmitry Torokhov Reviewed-by: Dmitry Torokhov Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 15 +++++++++++++-- 1 file changed, 13 insertions(+), 2 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index e901d2666b46..68dbff5d8f57 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -20,6 +20,7 @@ #include #include #include +#include #include #include "gpiolib.h" @@ -316,7 +317,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) { struct gpio_device *gdev = filp->private_data; struct gpio_chip *chip = gdev->chip; - int __user *ip = (int __user *)arg; + void __user *ip = (void __user *)arg; /* We fail any subsequent ioctl():s when the chip is gone */ if (!chip) @@ -388,6 +389,14 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) return -EINVAL; } +#ifdef CONFIG_COMPAT +static long gpio_ioctl_compat(struct file *filp, unsigned int cmd, + unsigned long arg) +{ + return gpio_ioctl(filp, cmd, (unsigned long)compat_ptr(arg)); +} +#endif + /** * gpio_chrdev_open() - open the chardev for ioctl operations * @inode: inode for this chardev @@ -431,7 +440,9 @@ static const struct file_operations gpio_fileops = { .owner = THIS_MODULE, .llseek = noop_llseek, .unlocked_ioctl = gpio_ioctl, - .compat_ioctl = gpio_ioctl, +#ifdef CONFIG_COMPAT + .compat_ioctl = gpio_ioctl_compat, +#endif }; static void gpiodevice_release(struct device *dev) -- cgit v1.2.3 From 54d77198fdfbc4f0fe11b4252c1d9c97d51a3264 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 30 May 2016 16:48:39 +0200 Subject: gpio: bail out silently on NULL descriptors MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit In fdeb8e1547cb9dd39d5d7223b33f3565cf86c28e ("gpio: reflect base and ngpio into gpio_device") assumed that GPIO descriptors are either valid or error pointers, but gpiod_get_[index_]optional() actually return NULL descriptors and then all subsequent calls should just bail out. Cc: stable@vger.kernel.org Cc: Sergei Shtylyov Cc: Florian Fainelli Cc: Andrew Lunn Fixes: fdeb8e1547cb ("gpio: reflect base and ngpio into gpio_device") Reported-by: Uwe Kleine-König Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 11 ++++++++--- 1 file changed, 8 insertions(+), 3 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 68dbff5d8f57..246b6b051b0d 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -1367,10 +1367,13 @@ done: /* * This descriptor validation needs to be inserted verbatim into each * function taking a descriptor, so we need to use a preprocessor - * macro to avoid endless duplication. + * macro to avoid endless duplication. If the desc is NULL it is an + * optional GPIO and calls should just bail out. */ #define VALIDATE_DESC(desc) do { \ - if (!desc || !desc->gdev) { \ + if (!desc) \ + return 0; \ + if (!desc->gdev) { \ pr_warn("%s: invalid GPIO\n", __func__); \ return -EINVAL; \ } \ @@ -1381,7 +1384,9 @@ done: } } while (0) #define VALIDATE_DESC_VOID(desc) do { \ - if (!desc || !desc->gdev) { \ + if (!desc) \ + return; \ + if (!desc->gdev) { \ pr_warn("%s: invalid GPIO\n", __func__); \ return; \ } \ -- cgit v1.2.3 From 545ebd9a9be6bcbcf3e8dc24b874bfd634131946 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Mon, 30 May 2016 17:11:59 +0200 Subject: gpio: drop lock before reading GPIO direction When adding the gpiochip, the GPIO HW drivers' callback get_direction() could get called in atomic context. Some of the GPIO HW drivers may sleep when accessing the register. Move the lock before initializing the descriptors. Reported-by: Laxman Dewangan Signed-off-by: Linus Walleij --- drivers/gpio/gpiolib.c | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) (limited to 'drivers/gpio/gpiolib.c') diff --git a/drivers/gpio/gpiolib.c b/drivers/gpio/gpiolib.c index 246b6b051b0d..24f60d28f0c0 100644 --- a/drivers/gpio/gpiolib.c +++ b/drivers/gpio/gpiolib.c @@ -629,6 +629,8 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) goto err_free_label; } + spin_unlock_irqrestore(&gpio_lock, flags); + for (i = 0; i < chip->ngpio; i++) { struct gpio_desc *desc = &gdev->descs[i]; @@ -660,8 +662,6 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) } } - spin_unlock_irqrestore(&gpio_lock, flags); - #ifdef CONFIG_PINCTRL INIT_LIST_HEAD(&gdev->pin_ranges); #endif -- cgit v1.2.3