When qcom_pas_attach() finds the fatal SMP2P bit already set, it reports a crash and then fails the attach. The core unwinds the attach while the crash work is queued: rproc_boot() drops the power refcount back to 0, and __rproc_attach()/rproc_attach() unprepare the subdevices, clean up the resource table and disable the IOMMU. Once rproc_boot() releases rproc->lock, the crash handler finds the rproc still RPROC_DETACHED, marks it RPROC_CRASHED and runs rproc_boot_recovery() on top of that torn-down state:
- the subdevices are unprepared a second time by rproc_stop(), so SSR and sysmon notifiers see a duplicate shutdown; - qcom_pas_stop() and the subsequent rproc_start() operate on resources that rproc_attach() already released, e.g. iommu_unmap() on a disabled domain for rproc->has_iommu; - recovery leaves the rproc RPROC_RUNNING with power == 0. A later "stop" via sysfs takes power to -1 and returns success without stopping anything, so the remote stays running. A following "start" then boots the firmware again on the running remote and fails to re-add the still registered subdevices: sysfs: cannot create duplicate filename '.../qcom_common.pd-mapper.0' remoteproc remoteproc0: failed to prepare subdevices for adsp: -17 remoteproc remoteproc0: Boot failed: -17 A crash found at attach time is no different from one reported by the fatal interrupt right after attaching. Factor the crash handling out of q6v5_fatal_interrupt() into qcom_q6v5_report_fatal(), which logs the SMEM crash reason, clears q6v5.running and reports the crash, and call it from qcom_pas_attach() before letting the attach succeed. The core completes the attach with balanced bookkeeping, and the crash handler then recovers the subsystem through the regular RPROC_ATTACHED -> RPROC_CRASHED path. With running cleared, qcom_q6v5_request_stop() does not wait for a stop ack the dead remote cannot send, and handover_issued already prevents a spurious handover on stop. Assisted-by: LLM Signed-off-by: Shawn Guo <[email protected]> --- drivers/remoteproc/qcom_q6v5.c | 22 +++++++++++++++++----- drivers/remoteproc/qcom_q6v5.h | 1 + drivers/remoteproc/qcom_q6v5_pas.c | 9 ++++++--- 3 files changed, 24 insertions(+), 8 deletions(-) diff --git a/drivers/remoteproc/qcom_q6v5.c b/drivers/remoteproc/qcom_q6v5.c index fe148b4b3775..51b24cbd4336 100644 --- a/drivers/remoteproc/qcom_q6v5.c +++ b/drivers/remoteproc/qcom_q6v5.c @@ -147,15 +147,18 @@ static irqreturn_t q6v5_wdog_interrupt(int irq, void *data) return IRQ_HANDLED; } -static irqreturn_t q6v5_fatal_interrupt(int irq, void *data) +/** + * qcom_q6v5_report_fatal() - report a fatal error of the remote processor + * @q6v5: reference to qcom_q6v5 context + * + * Log the crash reason published by the remote in SMEM, mark the remote as + * no longer running and report the crash to the remoteproc core. + */ +void qcom_q6v5_report_fatal(struct qcom_q6v5 *q6v5) { - struct qcom_q6v5 *q6v5 = data; size_t len; char *msg; - if (!q6v5->running) - return IRQ_HANDLED; - msg = qcom_smem_get(QCOM_SMEM_HOST_ANY, q6v5->crash_reason, &len); if (!IS_ERR(msg) && len > 0 && msg[0]) dev_err(q6v5->dev, "fatal error received: %s\n", msg); @@ -164,6 +167,15 @@ static irqreturn_t q6v5_fatal_interrupt(int irq, void *data) q6v5->running = false; rproc_report_crash(q6v5->rproc, RPROC_FATAL_ERROR); +} +EXPORT_SYMBOL_GPL(qcom_q6v5_report_fatal); + +static irqreturn_t q6v5_fatal_interrupt(int irq, void *data) +{ + struct qcom_q6v5 *q6v5 = data; + + if (q6v5->running) + qcom_q6v5_report_fatal(q6v5); return IRQ_HANDLED; } diff --git a/drivers/remoteproc/qcom_q6v5.h b/drivers/remoteproc/qcom_q6v5.h index 8991ff090579..a0507860a21c 100644 --- a/drivers/remoteproc/qcom_q6v5.h +++ b/drivers/remoteproc/qcom_q6v5.h @@ -56,5 +56,6 @@ int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5); int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5, struct qcom_sysmon *sysmon); int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout); unsigned long qcom_q6v5_panic(struct qcom_q6v5 *q6v5); +void qcom_q6v5_report_fatal(struct qcom_q6v5 *q6v5); #endif diff --git a/drivers/remoteproc/qcom_q6v5_pas.c b/drivers/remoteproc/qcom_q6v5_pas.c index 56179b71fd2a..99f627db6bd3 100644 --- a/drivers/remoteproc/qcom_q6v5_pas.c +++ b/drivers/remoteproc/qcom_q6v5_pas.c @@ -562,10 +562,13 @@ static int qcom_pas_attach(struct rproc *rproc) goto disable_running; if (crash_state) { + /* + * Complete the attach and let the crash handler recover the + * subsystem from the attached state, as for a crash reported + * by the fatal interrupt. + */ dev_err(pas->dev, "Subsystem has crashed before driver probe\n"); - rproc_report_crash(rproc, RPROC_FATAL_ERROR); - ret = -EINVAL; - goto disable_running; + qcom_q6v5_report_fatal(&pas->q6v5); } return 0; -- 2.43.0

