When qcom_pas_attach() is called (subsystem already running at kernel
probe time), it sets handover_issued = true before enabling the handover
IRQ. The handover line may be high already (from bootloader boot), causing
the IRQ to fire immediately. Since proxy resources were never acquired via
qcom_pas_pds_enable() in the attach path, the resulting handover callback
calls pm_runtime_put() on proxy power domains with usage count = 0:
genpd genpd:0:d00000.remoteproc: Runtime PM usage count underflow!
genpd genpd:1:d00000.remoteproc: Runtime PM usage count underflow!
Also, because the old code left handover_irq_enabled = false after attach
(fixed separately), the handover IRQ was never disabled inside the handler,
allowing it to fire repeatedly and generating multiple underflows.
Fix by recording whether handover_issued was already set before the IRQ
fires and skipping the handover callback in that case. The callback
releases proxy resources that are only held when the normal start path
ran qcom_pas_pds_enable(); if handover was already marked as issued,
those resources were never acquired and must not be released.
Fixes: 16472c99f469 ("remoteproc: qcom: pas: Add late attach support for
subsystems")
Signed-off-by: Mukesh Ojha <[email protected]>
---
drivers/remoteproc/qcom_q6v5.c | 8 +++++++-
1 file changed, 7 insertions(+), 1 deletion(-)
diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c
index fe148b4b3775..12ba0b80ad3e 100644
--- a/drivers/remoteproc/qcom_q6v5.c
+++ b/drivers/remoteproc/qcom_q6v5.c
@@ -198,12 +198,18 @@ EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_start);
static irqreturn_t q6v5_handover_interrupt(int irq, void *data)
{
struct qcom_q6v5 *q6v5 = data;
+ bool previously_issued;
+ previously_issued = q6v5->handover_issued;
q6v5->handover_issued = true;
q6v5_handover_irq_disable(q6v5, false);
- if (q6v5->handover)
+ /*
+ * Skip the handover callback if it was already issued (e.g. attach
+ * path), as the proxy resources were never acquired in that case.
+ */
+ if (!previously_issued && q6v5->handover)
q6v5->handover(q6v5);
icc_set_bw(q6v5->path, 0, 0);
--
2.55.0