[PATCH v2] gpio: dwapb: Add robust error handling in interrupt handler
From: Liang Hao
Date: Fri Jul 03 2026 - 10:34:40 EST
The current interrupt handler silently continues if an interrupt
handling fails, which may lead to interrupt storms. Add proper
error handling to gracefully recover from failed interrupt
handling.
When generic_handle_irq() fails, the following recovery actions are
taken:
- Write EOI to clear the pending interrupt
- Mask the interrupt to prevent immediate re-triggering
- Disable the interrupt to stop further interrupts on this line
Use scoped_guard(gpio_generic_lock_irqsave) to protect the read-
modify-write sequences on shared registers (GPIO_INTMASK and
GPIO_INTEN). This prevents race conditions with irq_chip callbacks
(dwapb_irq_mask, dwapb_irq_enable, etc.) that access the same
registers from different contexts.
These measures prevent the system from being overwhelmed by repeated
unhandled interrupts while logging a rate-limited warning for
debugging purposes.
Signed-off-by: Liang Hao <haohlliang@xxxxxxxxx>
---
v1 -> v2:
- Add spinlock protection for register access in error path
- Protect against race with irq_chip callbacks accessing shared registers
---
drivers/gpio/gpio-dwapb.c | 19 +++++++++++++++++--
1 file changed, 17 insertions(+), 2 deletions(-)
diff --git a/drivers/gpio/gpio-dwapb.c b/drivers/gpio/gpio-dwapb.c
index 7b92b233fafe..dc9676eb1429 100644
--- a/drivers/gpio/gpio-dwapb.c
+++ b/drivers/gpio/gpio-dwapb.c
@@ -209,8 +209,23 @@ static u32 dwapb_do_irq(struct dwapb_gpio *gpio)
for_each_set_bit(hwirq, &irq_status, DWAPB_MAX_GPIOS) {
int gpio_irq = irq_find_mapping(gen_gc->gc.irq.domain, hwirq);
u32 irq_type = irq_get_trigger_type(gpio_irq);
-
- generic_handle_irq(gpio_irq);
+ int ret;
+ u32 val_intmask, val_inten;
+
+ ret = generic_handle_irq(gpio_irq);
+ if (ret) {
+ dev_warn_ratelimited(gpio->dev, "Failed to handle irq %d\n", gpio_irq);
+ /* Clear the interrupt */
+ scoped_guard(gpio_generic_lock_irqsave, gen_gc) {
+ /* Clear the interrupt */
+ dwapb_write(gpio, GPIO_PORTA_EOI, BIT(hwirq));
+ val_intmask = dwapb_read(gpio, GPIO_INTMASK);
+ dwapb_write(gpio, GPIO_INTMASK, val_intmask | BIT(hwirq));
+ val_inten = dwapb_read(gpio, GPIO_INTEN);
+ dwapb_write(gpio, GPIO_INTEN, val_inten & ~BIT(hwirq));
+ }
+ continue;
+ }
if ((irq_type & IRQ_TYPE_SENSE_MASK) == IRQ_TYPE_EDGE_BOTH)
dwapb_toggle_trigger(gpio, hwirq);
--
2.50.1 (Apple Git-155)