Merge tag 'gpio-v4.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux...
authorLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 May 2016 16:27:00 +0000 (09:27 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Tue, 31 May 2016 16:27:00 +0000 (09:27 -0700)
Pull GPIO fixes from Linus Walleij:
 "A bunch of GPIO fixes for the v4.7 series:

   - Drop the lock before reading out the GPIO direction setting in
     drivers supporting the .get_direction() callback: some of them may
     be slowpath.

   - Flush GPIO direction setting before locking a GPIO as an IRQ: some
     electronics or other poking around in the registers behind our back
     may have happened, so flush the direction status before trying to
     lock the line for use by IRQs.

   - Bail out silently when asked to perform operations on NULL GPIO
     descriptors.  That is what all the get_*_optional() is about: we
     get optional GPIO handles, if they are not there, we get NULL.

   - Handle compatible ioctl() correctly: we need to convert the ioctl()
     pointer using compat_ptr() here like everyone else.

   - Disable the broken .to_irq() on the LPC32xx platform.  The whole
     irqchip infrastructure was replaced in the last merge window, and a
     new implementation will be needed"

* tag 'gpio-v4.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio:
  gpio: drop lock before reading GPIO direction
  gpio: bail out silently on NULL descriptors
  gpio: handle compatible ioctl() pointers
  gpio: flush direction status in gpiochip_lock_as_irq()
  gpio: lpc32xx: disable broken to_irq support

drivers/gpio/gpio-lpc32xx.c
drivers/gpio/gpiolib.c

index d39014daeef9e206bfeb8cdf967e3c55c56db459..fc5f197906ac97b09b14617ca56d52896b59453a 100644 (file)
@@ -29,7 +29,6 @@
 
 #include <mach/hardware.h>
 #include <mach/platform.h>
-#include <mach/irqs.h>
 
 #define LPC32XX_GPIO_P3_INP_STATE              _GPREG(0x000)
 #define LPC32XX_GPIO_P3_OUTP_SET               _GPREG(0x004)
@@ -371,61 +370,16 @@ static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin)
 
 static int lpc32xx_gpio_to_irq_p01(struct gpio_chip *chip, unsigned offset)
 {
-       return IRQ_LPC32XX_P0_P1_IRQ;
+       return -ENXIO;
 }
 
-static const char lpc32xx_gpio_to_irq_gpio_p3_table[] = {
-       IRQ_LPC32XX_GPIO_00,
-       IRQ_LPC32XX_GPIO_01,
-       IRQ_LPC32XX_GPIO_02,
-       IRQ_LPC32XX_GPIO_03,
-       IRQ_LPC32XX_GPIO_04,
-       IRQ_LPC32XX_GPIO_05,
-};
-
 static int lpc32xx_gpio_to_irq_gpio_p3(struct gpio_chip *chip, unsigned offset)
 {
-       if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpio_p3_table))
-               return lpc32xx_gpio_to_irq_gpio_p3_table[offset];
        return -ENXIO;
 }
 
-static const char lpc32xx_gpio_to_irq_gpi_p3_table[] = {
-       IRQ_LPC32XX_GPI_00,
-       IRQ_LPC32XX_GPI_01,
-       IRQ_LPC32XX_GPI_02,
-       IRQ_LPC32XX_GPI_03,
-       IRQ_LPC32XX_GPI_04,
-       IRQ_LPC32XX_GPI_05,
-       IRQ_LPC32XX_GPI_06,
-       IRQ_LPC32XX_GPI_07,
-       IRQ_LPC32XX_GPI_08,
-       IRQ_LPC32XX_GPI_09,
-       -ENXIO, /* 10 */
-       -ENXIO, /* 11 */
-       -ENXIO, /* 12 */
-       -ENXIO, /* 13 */
-       -ENXIO, /* 14 */
-       -ENXIO, /* 15 */
-       -ENXIO, /* 16 */
-       -ENXIO, /* 17 */
-       -ENXIO, /* 18 */
-       IRQ_LPC32XX_GPI_19,
-       -ENXIO, /* 20 */
-       -ENXIO, /* 21 */
-       -ENXIO, /* 22 */
-       -ENXIO, /* 23 */
-       -ENXIO, /* 24 */
-       -ENXIO, /* 25 */
-       -ENXIO, /* 26 */
-       -ENXIO, /* 27 */
-       IRQ_LPC32XX_GPI_28,
-};
-
 static int lpc32xx_gpio_to_irq_gpi_p3(struct gpio_chip *chip, unsigned offset)
 {
-       if (offset < ARRAY_SIZE(lpc32xx_gpio_to_irq_gpi_p3_table))
-               return lpc32xx_gpio_to_irq_gpi_p3_table[offset];
        return -ENXIO;
 }
 
index d407f904a31cf475647d2624ac84cd5f624c425d..24f60d28f0c055dbddfcd2750737534071813d26 100644 (file)
@@ -20,6 +20,7 @@
 #include <linux/cdev.h>
 #include <linux/fs.h>
 #include <linux/uaccess.h>
+#include <linux/compat.h>
 #include <uapi/linux/gpio.h>
 
 #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)
@@ -618,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];
 
@@ -649,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
@@ -1356,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; \
        } \
@@ -1370,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; \
        } \
@@ -2066,17 +2082,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);