[PATCH 2/2] remoteproc: qcom: q6v5: Ignore stale handover IRQ delivered on attach
Shawn Guo <[email protected]> Fri, 31 Jul 2026 10:56:54 +0800
| Newsgroups | org.kernel.vger.linux-remoteproc,org.kernel.vger.linux-arm-msm,org.kernel.vger.linux-kernel |
|---|---|
| Message-ID | <[email protected]> |
Commit bb7c5d6f5b41 ("remoteproc: qcom: q6v5: Make handover IRQ one-shot")
dropped the check that ignored a handover interrupt after handover
had already been issued, relying instead on disabling the IRQ after
its first delivery to make it one-shot.
That is not sufficient for qcom_pas_attach(): when attaching to a
remote processor that was already booted by the bootloader, handover
has already happened out-of-band, before this driver ever probed.
qcom_pas_attach() sets handover_issued = true and unmasks the
handover IRQ to keep the enable/disable tracking consistent, but the
transition that signals handover is latched at the interrupt
controller while masked, so unmasking still delivers that one IRQ.
Since this driver instance never ran qcom_pas_start() for that boot,
it never took the proxy power-domain/clock/regulator votes that
q6v5->handover() releases. Running the handover callback for this
stale, already-accounted-for signal disables those votes without a
matching enable, producing:
genpd genpd:0:4c00000.remoteproc: Runtime PM usage count underflow!
genpd genpd:1:4c00000.remoteproc: Runtime PM usage count underflow!
Restore the early-return when handover_issued is already set, so a
stale IRQ delivered on attach is dropped after being disabled instead
of re-running the handover callback.
Fixes: bb7c5d6f5b41 ("remoteproc: qcom: q6v5: Make handover IRQ one-shot")
Assisted-by: Claude:claude-sonnet-5
Signed-off-by: Shawn Guo <[email protected]>
---
drivers/remoteproc/qcom_q6v5.c | 17 +++++++++++++++--
1 file changed, 15 insertions(+), 2 deletions(-)
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index 10fa38f264c8..e715083846aa 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -210,10 +210,23 @@ static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
- q6v5->handover_issued = true;
-
qcom_q6v5_handover_irq_disable(q6v5, false);
+ /*
+ * When attaching to an already-running remote processor,
+ * handover_issued is set before the IRQ is unmasked, since the
+ * handover already happened out-of-band, before this driver probed.
+ * The transition that signals it is latched at the interrupt
+ * controller while masked, so unmasking still delivers this one
+ * IRQ. Ignore it: this driver instance never enabled the resources
+ * (proxy PDs, clocks, etc.) that the handover callback would tear
+ * down.
+ */
+ if (q6v5->handover_issued)
+ return IRQ_HANDLED;
+
+ q6v5->handover_issued = true;
+
if (q6v5->handover)
q6v5->handover(q6v5);
--
2.43.0