6.18-stable review patch. If anyone has any objections, please let me know. ------------------ From: Mark Tomlinson [ Upstream commit 9dc325327babe7f159e84cbe9380a45342da0585 ] Locking is disabled in the regmap config as this driver uses its own lock. This means that all calls to regmap functions (read or write) must hold the i2c_lock. The function pca953x_irq_bus_sync_unlock() did not do this, and it was therefore possible that multiple threads could cause an incorrect register to be read/written. A previous patch partly fixed this, but only protected the write to the interrupt mask register, and not the read from the direction register. Fixes: bfc6444b57dc ("gpio: pca953x: fix pca953x_irq_bus_sync_unlock race") Cc: stable@vger.kernel.org Signed-off-by: Mark Tomlinson Link: https://patch.msgid.link/20260709045116.2304246-1-mark.tomlinson@alliedtelesis.co.nz Signed-off-by: Bartosz Golaszewski Signed-off-by: Sasha Levin --- drivers/gpio/gpio-pca953x.c | 20 ++++++++++++++------ 1 file changed, 14 insertions(+), 6 deletions(-) diff --git a/drivers/gpio/gpio-pca953x.c b/drivers/gpio/gpio-pca953x.c index b18a2d0f6984e..4eeac12ad0ed3 100644 --- a/drivers/gpio/gpio-pca953x.c +++ b/drivers/gpio/gpio-pca953x.c @@ -605,20 +605,28 @@ static int pca953x_read_regs(struct pca953x_chip *chip, int reg, unsigned long * return 0; } -static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned off) +static int pca953x_gpio_direction_input_unlocked(struct gpio_chip *gc, + unsigned int off) { struct pca953x_chip *chip = gpiochip_get_data(gc); u8 dirreg = chip->recalc_addr(chip, chip->regs->direction, off); u8 bit = pca953x_get_bit_mask(chip, off); - guard(mutex)(&chip->i2c_lock); - if (PCA_CHIP_TYPE(chip->driver_data) == TCA6418_TYPE) return regmap_update_bits(chip->regmap, dirreg, bit, 0); return regmap_update_bits(chip->regmap, dirreg, bit, bit); } +static int pca953x_gpio_direction_input(struct gpio_chip *gc, unsigned int off) +{ + struct pca953x_chip *chip = gpiochip_get_data(gc); + + guard(mutex)(&chip->i2c_lock); + + return pca953x_gpio_direction_input_unlocked(gc, off); +} + static int pca953x_gpio_direction_output(struct gpio_chip *gc, unsigned off, int val) { @@ -856,9 +864,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) DECLARE_BITMAP(reg_direction, MAX_LINE); int level; - if (chip->driver_data & PCA_PCAL) { - guard(mutex)(&chip->i2c_lock); + guard(mutex)(&chip->i2c_lock); + if (chip->driver_data & PCA_PCAL) { /* Enable latch on interrupt-enabled inputs */ pca953x_write_regs(chip, PCAL953X_IN_LATCH, chip->irq_mask); @@ -879,7 +887,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d) /* Look for any newly setup interrupt */ for_each_set_bit(level, irq_mask, gc->ngpio) - pca953x_gpio_direction_input(&chip->gpio_chip, level); + pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level); mutex_unlock(&chip->irq_lock); } -- 2.53.0