Firmware on clustered remote processors (e.g. Nord's HPASS ADSP0/1/2)
cannot handle the SSCTL peer-shutdown notification sysmon sends
whenever a sibling in the same cluster starts or stops, and the QMI
request instead times out.

Skip sysmon_notify() when the notifying and the notified instance share
the cluster identifier their owning rproc driver put in rproc->cluster.
The suppression is done on the receiving side, so that a cluster member
keeps notifying, and being notified by, remote processors outside its
cluster. Instances whose rproc has no cluster set are completely
unaffected.

Assisted-by: LLM
Signed-off-by: Shawn Guo <[email protected]>
---
 drivers/remoteproc/qcom_sysmon.c | 18 ++++++++++++++----
 1 file changed, 14 insertions(+), 4 deletions(-)

diff --git a/drivers/remoteproc/qcom_sysmon.c b/drivers/remoteproc/qcom_sysmon.c
index 61e1038328e8..5d4443ef3bc1 100644
--- a/drivers/remoteproc/qcom_sysmon.c
+++ b/drivers/remoteproc/qcom_sysmon.c
@@ -67,6 +67,7 @@ static const char * const sysmon_state_string[] = {
 struct sysmon_event {
        const char *subsys_name;
        u32 ssr_event;
+       void *cluster;
 };
 
 static DEFINE_MUTEX(sysmon_lock);
@@ -473,7 +474,8 @@ static int sysmon_prepare(struct rproc_subdev *subdev)
                                                  subdev);
        struct sysmon_event event = {
                .subsys_name = sysmon->name,
-               .ssr_event = SSCTL_SSR_EVENT_BEFORE_POWERUP
+               .ssr_event = SSCTL_SSR_EVENT_BEFORE_POWERUP,
+               .cluster = sysmon->rproc->cluster,
        };
 
        mutex_lock(&sysmon->state_lock);
@@ -500,7 +502,8 @@ static int sysmon_start(struct rproc_subdev *subdev)
        struct qcom_sysmon *target;
        struct sysmon_event event = {
                .subsys_name = sysmon->name,
-               .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP
+               .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP,
+               .cluster = sysmon->rproc->cluster,
        };
 
        reinit_completion(&sysmon->ssctl_comp);
@@ -536,7 +539,8 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool 
crashed)
        struct qcom_sysmon *sysmon = container_of(subdev, struct qcom_sysmon, 
subdev);
        struct sysmon_event event = {
                .subsys_name = sysmon->name,
-               .ssr_event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN
+               .ssr_event = SSCTL_SSR_EVENT_BEFORE_SHUTDOWN,
+               .cluster = sysmon->rproc->cluster,
        };
 
        sysmon->shutdown_acked = false;
@@ -567,7 +571,8 @@ static void sysmon_unprepare(struct rproc_subdev *subdev)
                                                  subdev);
        struct sysmon_event event = {
                .subsys_name = sysmon->name,
-               .ssr_event = SSCTL_SSR_EVENT_AFTER_SHUTDOWN
+               .ssr_event = SSCTL_SSR_EVENT_AFTER_SHUTDOWN,
+               .cluster = sysmon->rproc->cluster,
        };
 
        mutex_lock(&sysmon->state_lock);
@@ -588,6 +593,11 @@ static int sysmon_notify(struct notifier_block *nb, 
unsigned long event,
        struct qcom_sysmon *sysmon = container_of(nb, struct qcom_sysmon, nb);
        struct sysmon_event *sysmon_event = data;
 
+       /* Cluster siblings' firmware can't handle peer SSR notify; skip it */
+       if (sysmon->rproc->cluster &&
+           sysmon->rproc->cluster == sysmon_event->cluster)
+               return NOTIFY_DONE;
+
        /* Skip non-running rprocs and the originating instance */
        if (sysmon->state != SSCTL_SSR_EVENT_AFTER_POWERUP ||
            !strcmp(sysmon_event->subsys_name, sysmon->name)) {
-- 
2.43.0


Reply via email to