Commit 5eca8317 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-v4.7-2' of git://git.kernel.org/pub/scm/linux/kernel/git/linusw/linux-gpio

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
parents 852f42a6 545ebd9a
...@@ -29,7 +29,6 @@ ...@@ -29,7 +29,6 @@
#include <mach/hardware.h> #include <mach/hardware.h>
#include <mach/platform.h> #include <mach/platform.h>
#include <mach/irqs.h>
#define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000) #define LPC32XX_GPIO_P3_INP_STATE _GPREG(0x000)
#define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004) #define LPC32XX_GPIO_P3_OUTP_SET _GPREG(0x004)
...@@ -371,61 +370,16 @@ static int lpc32xx_gpio_request(struct gpio_chip *chip, unsigned pin) ...@@ -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) 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) 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; 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) 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; return -ENXIO;
} }
......
...@@ -20,6 +20,7 @@ ...@@ -20,6 +20,7 @@
#include <linux/cdev.h> #include <linux/cdev.h>
#include <linux/fs.h> #include <linux/fs.h>
#include <linux/uaccess.h> #include <linux/uaccess.h>
#include <linux/compat.h>
#include <uapi/linux/gpio.h> #include <uapi/linux/gpio.h>
#include "gpiolib.h" #include "gpiolib.h"
...@@ -316,7 +317,7 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -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_device *gdev = filp->private_data;
struct gpio_chip *chip = gdev->chip; 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 */ /* We fail any subsequent ioctl():s when the chip is gone */
if (!chip) if (!chip)
...@@ -388,6 +389,14 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg) ...@@ -388,6 +389,14 @@ static long gpio_ioctl(struct file *filp, unsigned int cmd, unsigned long arg)
return -EINVAL; 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 * gpio_chrdev_open() - open the chardev for ioctl operations
* @inode: inode for this chardev * @inode: inode for this chardev
...@@ -431,7 +440,9 @@ static const struct file_operations gpio_fileops = { ...@@ -431,7 +440,9 @@ static const struct file_operations gpio_fileops = {
.owner = THIS_MODULE, .owner = THIS_MODULE,
.llseek = noop_llseek, .llseek = noop_llseek,
.unlocked_ioctl = gpio_ioctl, .unlocked_ioctl = gpio_ioctl,
.compat_ioctl = gpio_ioctl, #ifdef CONFIG_COMPAT
.compat_ioctl = gpio_ioctl_compat,
#endif
}; };
static void gpiodevice_release(struct device *dev) static void gpiodevice_release(struct device *dev)
...@@ -618,6 +629,8 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) ...@@ -618,6 +629,8 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
goto err_free_label; goto err_free_label;
} }
spin_unlock_irqrestore(&gpio_lock, flags);
for (i = 0; i < chip->ngpio; i++) { for (i = 0; i < chip->ngpio; i++) {
struct gpio_desc *desc = &gdev->descs[i]; struct gpio_desc *desc = &gdev->descs[i];
...@@ -649,8 +662,6 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data) ...@@ -649,8 +662,6 @@ int gpiochip_add_data(struct gpio_chip *chip, void *data)
} }
} }
spin_unlock_irqrestore(&gpio_lock, flags);
#ifdef CONFIG_PINCTRL #ifdef CONFIG_PINCTRL
INIT_LIST_HEAD(&gdev->pin_ranges); INIT_LIST_HEAD(&gdev->pin_ranges);
#endif #endif
...@@ -1356,10 +1367,13 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) ...@@ -1356,10 +1367,13 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
/* /*
* This descriptor validation needs to be inserted verbatim into each * This descriptor validation needs to be inserted verbatim into each
* function taking a descriptor, so we need to use a preprocessor * 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 { \ #define VALIDATE_DESC(desc) do { \
if (!desc || !desc->gdev) { \ if (!desc) \
return 0; \
if (!desc->gdev) { \
pr_warn("%s: invalid GPIO\n", __func__); \ pr_warn("%s: invalid GPIO\n", __func__); \
return -EINVAL; \ return -EINVAL; \
} \ } \
...@@ -1370,7 +1384,9 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label) ...@@ -1370,7 +1384,9 @@ static int __gpiod_request(struct gpio_desc *desc, const char *label)
} } while (0) } } while (0)
#define VALIDATE_DESC_VOID(desc) do { \ #define VALIDATE_DESC_VOID(desc) do { \
if (!desc || !desc->gdev) { \ if (!desc) \
return; \
if (!desc->gdev) { \
pr_warn("%s: invalid GPIO\n", __func__); \ pr_warn("%s: invalid GPIO\n", __func__); \
return; \ return; \
} \ } \
...@@ -2066,17 +2082,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq); ...@@ -2066,17 +2082,30 @@ EXPORT_SYMBOL_GPL(gpiod_to_irq);
*/ */
int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset) int gpiochip_lock_as_irq(struct gpio_chip *chip, unsigned int offset)
{ {
if (offset >= chip->ngpio) struct gpio_desc *desc;
return -EINVAL;
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, chip_err(chip,
"%s: tried to flag a GPIO set as output for IRQ\n", "%s: tried to flag a GPIO set as output for IRQ\n",
__func__); __func__);
return -EIO; return -EIO;
} }
set_bit(FLAG_USED_AS_IRQ, &chip->gpiodev->descs[offset].flags); set_bit(FLAG_USED_AS_IRQ, &desc->flags);
return 0; return 0;
} }
EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq); EXPORT_SYMBOL_GPL(gpiochip_lock_as_irq);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment