From b96967644c524d34b2fdd2e58c31e7b36e3469e6 Mon Sep 17 00:00:00 2001 From: Linus Walleij Date: Sun, 27 Sep 2026 11:03:21 +0200 Subject: [PATCH] dmaengine: ste_dma40: Return IRQ_NONE when no interrupt is pending d40_handle_interrupt() returns IRQ_HANDLED even when no terminal-count or error status bit is pending. IRQ_NONE is not only used to identify a device on a shared interrupt. The generic IRQ core also counts it as unhandled for spurious IRQ detection. DMA40 does not request this IRQ with IRQF_SHARED, so interrupt sharing is not the purpose of this change. If the line remains asserted without matching DMA40 status, returning IRQ_HANDLED hides the stuck interrupt and can leave the CPU servicing it indefinitely. Track whether any DMA40 status is pending and return IRQ_NONE when none is present, allowing the generic IRQ core to diagnose and eventually disable the faulty line. DMA40 channels can be owned by other SoC cores. Their status means that the interrupt is real, but Linux must not acknowledge it. Treat foreign status as handled and leave its acknowledgment to the owning core, while acknowledging and dispatching only registered Linux channels. Fixes: 8d318a50b3d7 ("DMAENGINE: Support for ST-Ericssons DMA40 block v3") Assisted-by: LLM Reviewed-by: Frank Li Signed-off-by: Linus Walleij Link: https://patch.msgid.link/20260927-dma40-fixes-v7-8-89f595e8851d@kernel.org Signed-off-by: Vinod Koul --- drivers/dma/ste_dma40.c | 9 ++++++++- 1 file changed, 8 insertions(+), 1 deletion(-) diff --git a/drivers/dma/ste_dma40.c b/drivers/dma/ste_dma40.c index 03c43116e3ec..fddafa8c4886 100644 --- a/drivers/dma/ste_dma40.c +++ b/drivers/dma/ste_dma40.c @@ -1811,6 +1811,7 @@ static void dma_tasklet(struct tasklet_struct *t) static irqreturn_t d40_handle_interrupt(int irq, void *data) { + irqreturn_t handled = IRQ_NONE; int i; u32 idx; u32 row; @@ -1844,6 +1845,12 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data) row = chan / BITS_PER_LONG; idx = chan & (BITS_PER_LONG - 1); + /* + * Status for a channel owned by another core still explains + * the interrupt, but only ACK Linux-owned channels below. + */ + handled = IRQ_HANDLED; + if (il[row].offset == D40_PHY_CHAN) d40c = base->lookup_phy_chans[idx]; else @@ -1876,7 +1883,7 @@ static irqreturn_t d40_handle_interrupt(int irq, void *data) if (ret > 0) pm_runtime_put_autosuspend(base->dev); - return IRQ_HANDLED; + return handled; } static int d40_validate_conf(struct d40_chan *d40c,