]> git.ipfire.org Git - thirdparty/linux.git/commitdiff
i3c: master: svc: Prevent IRQ storm from false SLVSTART on NPCM845
authorStanley Chu <yschu@nuvoton.com>
Mon, 13 Apr 2026 00:50:40 +0000 (08:50 +0800)
committerAlexandre Belloni <alexandre.belloni@bootlin.com>
Thu, 30 Apr 2026 10:00:36 +0000 (12:00 +0200)
On NPCM845, when a target on the I3C bus gets stuck holding SDA low,
the controller reports a false Master Request (MR) in-band interrupt
event. The driver handles this by emitting a STOP condition to restore
the bus.

However, the hardware quirk SVC_I3C_QUIRK_FALSE_SLVSTART indicates that
emitting a STOP condition may spuriously set the SLVSTART interrupt
status bit. In the Master Request case, this creates a feedback loop:
the STOP triggers a new SLVSTART event, the IRQ handler fires again,
the controller still reports an MR type, another STOP is emitted, and
the cycle repeats indefinitely, resulting in an IRQ storm that can lock
up the CPU.

Clear the SLVSTART status bit explicitly after emitting the STOP in the
Master Request IBI handler when the SVC_I3C_QUIRK_FALSE_SLVSTART quirk
is set. This breaks the feedback loop without affecting normal SLVSTART
processing, which is already guarded in the top-level IRQ handler by
checking that MSTATUS is in SLVREQ state.

Signed-off-by: Stanley Chu <yschu@nuvoton.com>
Reviewed-by: Frank Li <Frank.Li@nxp.com>
Link: https://patch.msgid.link/20260413005040.1211107-3-yschu@nuvoton.com
Signed-off-by: Alexandre Belloni <alexandre.belloni@bootlin.com>
drivers/i3c/master/svc-i3c-master.c

index 63063741fbd12978d12483cc361ca499053761af..57d63d299e1efc888d6d5bdf288202196ef414cf 100644 (file)
@@ -655,6 +655,15 @@ static void svc_i3c_master_ibi_isr(struct svc_i3c_master *master)
                break;
        case SVC_I3C_MSTATUS_IBITYPE_MASTER_REQUEST:
                svc_i3c_master_emit_stop(master);
+
+               /*
+                * If a target gets stuck holding SDA low, the controller reports a MR.
+                * On NPCM845, emitting STOP may spuriously set SLVSTART, retriggering
+                * the interrupt and re-entering MR handling, leading to an IRQ storm.
+                * Clear SLVSTART after STOP to break the loop.
+                */
+               if (svc_has_quirk(master, SVC_I3C_QUIRK_FALSE_SLVSTART))
+                       writel(SVC_I3C_MINT_SLVSTART, master->regs + SVC_I3C_MSTATUS);
                break;
        default:
                break;