Commit 1cf06684 authored by Linus Torvalds's avatar Linus Torvalds

Merge tag 'gpio-fixes-for-v6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux

Pull gpio fixes from Bartosz Golaszewski:
 "An assortment of driver fixes and two commits addressing a bad
  behavior of the GPIO uAPI when reconfiguring requested lines.

   - fix a race condition in i2c transfers by adding a missing i2c lock
     section in gpio-pca953x

   - validate the number of obtained interrupts in gpio-davinci

   - add missing raw_spinlock_init() in gpio-graniterapids

   - fix bad character device behavior: disallow GPIO line
     reconfiguration without set direction both in v1 and v2 uAPI"

* tag 'gpio-fixes-for-v6.10-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/brgl/linux:
  gpiolib: cdev: Ignore reconfiguration without direction
  gpiolib: cdev: Disallow reconfiguration without direction (uAPI v1)
  gpio: graniterapids: Add missing raw_spinlock_init()
  gpio: davinci: Validate the obtained number of IRQs
  gpio: pca953x: fix pca953x_irq_bus_sync_unlock race
parents 90384559 b4403963
...@@ -225,6 +225,11 @@ static int davinci_gpio_probe(struct platform_device *pdev) ...@@ -225,6 +225,11 @@ static int davinci_gpio_probe(struct platform_device *pdev)
else else
nirq = DIV_ROUND_UP(ngpio, 16); nirq = DIV_ROUND_UP(ngpio, 16);
if (nirq > MAX_INT_PER_BANK) {
dev_err(dev, "Too many IRQs!\n");
return -EINVAL;
}
chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL); chips = devm_kzalloc(dev, sizeof(*chips), GFP_KERNEL);
if (!chips) if (!chips)
return -ENOMEM; return -ENOMEM;
......
...@@ -296,6 +296,8 @@ static int gnr_gpio_probe(struct platform_device *pdev) ...@@ -296,6 +296,8 @@ static int gnr_gpio_probe(struct platform_device *pdev)
if (!priv) if (!priv)
return -ENOMEM; return -ENOMEM;
raw_spin_lock_init(&priv->lock);
regs = devm_platform_ioremap_resource(pdev, 0); regs = devm_platform_ioremap_resource(pdev, 0);
if (IS_ERR(regs)) if (IS_ERR(regs))
return PTR_ERR(regs); return PTR_ERR(regs);
......
...@@ -758,6 +758,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) ...@@ -758,6 +758,8 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
int level; int level;
if (chip->driver_data & PCA_PCAL) { if (chip->driver_data & PCA_PCAL) {
guard(mutex)(&chip->i2c_lock);
/* Enable latch on interrupt-enabled inputs */ /* Enable latch on interrupt-enabled inputs */
pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask);
......
...@@ -89,6 +89,10 @@ struct linehandle_state { ...@@ -89,6 +89,10 @@ struct linehandle_state {
GPIOHANDLE_REQUEST_OPEN_DRAIN | \ GPIOHANDLE_REQUEST_OPEN_DRAIN | \
GPIOHANDLE_REQUEST_OPEN_SOURCE) GPIOHANDLE_REQUEST_OPEN_SOURCE)
#define GPIOHANDLE_REQUEST_DIRECTION_FLAGS \
(GPIOHANDLE_REQUEST_INPUT | \
GPIOHANDLE_REQUEST_OUTPUT)
static int linehandle_validate_flags(u32 flags) static int linehandle_validate_flags(u32 flags)
{ {
/* Return an error if an unknown flag is set */ /* Return an error if an unknown flag is set */
...@@ -169,21 +173,21 @@ static long linehandle_set_config(struct linehandle_state *lh, ...@@ -169,21 +173,21 @@ static long linehandle_set_config(struct linehandle_state *lh,
if (ret) if (ret)
return ret; return ret;
/* Lines must be reconfigured explicitly as input or output. */
if (!(lflags & GPIOHANDLE_REQUEST_DIRECTION_FLAGS))
return -EINVAL;
for (i = 0; i < lh->num_descs; i++) { for (i = 0; i < lh->num_descs; i++) {
desc = lh->descs[i]; desc = lh->descs[i];
linehandle_flags_to_desc_flags(gcnf.flags, &desc->flags); linehandle_flags_to_desc_flags(lflags, &desc->flags);
/*
* Lines have to be requested explicitly for input
* or output, else the line will be treated "as is".
*/
if (lflags & GPIOHANDLE_REQUEST_OUTPUT) { if (lflags & GPIOHANDLE_REQUEST_OUTPUT) {
int val = !!gcnf.default_values[i]; int val = !!gcnf.default_values[i];
ret = gpiod_direction_output(desc, val); ret = gpiod_direction_output(desc, val);
if (ret) if (ret)
return ret; return ret;
} else if (lflags & GPIOHANDLE_REQUEST_INPUT) { } else {
ret = gpiod_direction_input(desc); ret = gpiod_direction_input(desc);
if (ret) if (ret)
return ret; return ret;
...@@ -1530,12 +1534,14 @@ static long linereq_set_config(struct linereq *lr, void __user *ip) ...@@ -1530,12 +1534,14 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
line = &lr->lines[i]; line = &lr->lines[i];
desc = lr->lines[i].desc; desc = lr->lines[i].desc;
flags = gpio_v2_line_config_flags(&lc, i); flags = gpio_v2_line_config_flags(&lc, i);
gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags);
edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
/* /*
* Lines have to be requested explicitly for input * Lines not explicitly reconfigured as input or output
* or output, else the line will be treated "as is". * are left unchanged.
*/ */
if (!(flags & GPIO_V2_LINE_DIRECTION_FLAGS))
continue;
gpio_v2_line_config_flags_to_desc_flags(flags, &desc->flags);
edflags = flags & GPIO_V2_LINE_EDGE_DETECTOR_FLAGS;
if (flags & GPIO_V2_LINE_FLAG_OUTPUT) { if (flags & GPIO_V2_LINE_FLAG_OUTPUT) {
int val = gpio_v2_line_config_output_value(&lc, i); int val = gpio_v2_line_config_output_value(&lc, i);
...@@ -1543,7 +1549,7 @@ static long linereq_set_config(struct linereq *lr, void __user *ip) ...@@ -1543,7 +1549,7 @@ static long linereq_set_config(struct linereq *lr, void __user *ip)
ret = gpiod_direction_output(desc, val); ret = gpiod_direction_output(desc, val);
if (ret) if (ret)
return ret; return ret;
} else if (flags & GPIO_V2_LINE_FLAG_INPUT) { } else {
ret = gpiod_direction_input(desc); ret = gpiod_direction_input(desc);
if (ret) if (ret)
return ret; return ret;
......
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