mirror of
https://github.com/torvalds/linux.git
synced 2026-11-07 06:17:02 +01:00
gpio: pca953x: Handle direction register read errors in IRQ paths
Three IRQ paths ignore the result of reading the direction registers
and then use the destination bitmap. pca953x_read_regs() does not populate
that bitmap when regmap_bulk_read() fails, leaving the callers to use
uninitialized stack data.
This can select incorrect GPIOs for direction changes during IRQ bus
synchronization, corrupt the saved input state during IRQ setup, or
produce incorrect pending interrupt decisions.
Check the read result at all three sites. Release irq_lock without
changing GPIO directions on failure, leave the IRQ history untouched
when pending detection fails, and propagate the error from IRQ setup.
The read helper already logs the error.
Fixes: 0f25fda840 ("gpio: pca953x: Zap ad-hoc reg_direction cache")
Cc: stable@vger.kernel.org
Signed-off-by: Sahaj Chaudhari <sahaj123.sc@gmail.com>
Link: https://patch.msgid.link/20261018165003.3372368-1-sahaj123.sc@gmail.com
Signed-off-by: Bartosz Golaszewski <bartosz.golaszewski@oss.qualcomm.com>
This commit is contained in:
parent
a38bf55172
commit
a0fe269293
|
|
@ -867,6 +867,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
DECLARE_BITMAP(irq_mask, MAX_LINE);
|
||||
DECLARE_BITMAP(reg_direction, MAX_LINE);
|
||||
int level;
|
||||
int ret;
|
||||
|
||||
guard(mutex)(&chip->i2c_lock);
|
||||
|
||||
|
|
@ -885,7 +886,9 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
}
|
||||
|
||||
/* Switch direction to input if needed */
|
||||
pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
bitmap_or(irq_mask, chip->irq_trig_fall, chip->irq_trig_raise, gc->ngpio);
|
||||
bitmap_or(irq_mask, irq_mask, chip->irq_trig_level_high, gc->ngpio);
|
||||
|
|
@ -895,6 +898,7 @@ static void pca953x_irq_bus_sync_unlock(struct irq_data *d)
|
|||
for_each_andnot_bit(level, irq_mask, reg_direction, gc->ngpio)
|
||||
pca953x_gpio_direction_input_unlocked(&chip->gpio_chip, level);
|
||||
|
||||
out:
|
||||
mutex_unlock(&chip->irq_lock);
|
||||
}
|
||||
|
||||
|
|
@ -989,7 +993,9 @@ static bool pca953x_irq_pending(struct pca953x_chip *chip, unsigned long *pendin
|
|||
}
|
||||
|
||||
/* Remove output pins from the equation */
|
||||
pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
if (ret)
|
||||
return false;
|
||||
|
||||
bitmap_copy(old_stat, chip->irq_stat, gc->ngpio);
|
||||
|
||||
|
|
@ -1089,7 +1095,9 @@ static int pca953x_irq_setup(struct pca953x_chip *chip, int irq_base)
|
|||
* interrupt. We have to rely on the previous read for
|
||||
* this purpose.
|
||||
*/
|
||||
pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
ret = pca953x_read_regs(chip, chip->regs->direction, reg_direction);
|
||||
if (ret)
|
||||
return ret;
|
||||
bitmap_and(chip->irq_stat, irq_stat, reg_direction, gc->ngpio);
|
||||
mutex_init(&chip->irq_lock);
|
||||
|
||||
|
|
|
|||
Loading…
Reference in New Issue
Block a user