remoteproc: sysmon: Wait for SSCTL service to come up
authorSibi Sankar <quic_sibis@quicinc.com>
Tue, 5 Jul 2022 12:08:19 +0000 (17:38 +0530)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Wed, 17 Aug 2022 12:24:09 +0000 (14:24 +0200)
[ Upstream commit 47c04e00eff86a81cd357c3feed04c86089bcb85 ]

The SSCTL service comes up after a finite time when the remote Q6 comes
out of reset. Any graceful shutdowns requested during this period will
be a NOP and abrupt tearing down of the glink channel might lead to pending
transactions on the remote Q6 side and will ultimately lead to a fatal
error. Fix this by waiting for the SSCTL service when a graceful shutdown
is requested.

Fixes: 1fb82ee806d1 ("remoteproc: qcom: Introduce sysmon")
Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
Signed-off-by: Sibi Sankar <quic_sibis@quicinc.com>
Signed-off-by: Bjorn Andersson <bjorn.andersson@linaro.org>
Link: https://lore.kernel.org/r/1657022900-2049-7-git-send-email-quic_sibis@quicinc.com
Signed-off-by: Sasha Levin <sashal@kernel.org>
drivers/remoteproc/qcom_sysmon.c

index 9fca814..a9f04dd 100644 (file)
@@ -41,6 +41,7 @@ struct qcom_sysmon {
        struct completion comp;
        struct completion ind_comp;
        struct completion shutdown_comp;
+       struct completion ssctl_comp;
        struct mutex lock;
 
        bool ssr_ack;
@@ -445,6 +446,8 @@ static int ssctl_new_server(struct qmi_handle *qmi, struct qmi_service *svc)
 
        svc->priv = sysmon;
 
+       complete(&sysmon->ssctl_comp);
+
        return 0;
 }
 
@@ -501,6 +504,7 @@ static int sysmon_start(struct rproc_subdev *subdev)
                .ssr_event = SSCTL_SSR_EVENT_AFTER_POWERUP
        };
 
+       reinit_completion(&sysmon->ssctl_comp);
        mutex_lock(&sysmon->state_lock);
        sysmon->state = SSCTL_SSR_EVENT_AFTER_POWERUP;
        blocking_notifier_call_chain(&sysmon_notifiers, 0, (void *)&event);
@@ -545,6 +549,11 @@ static void sysmon_stop(struct rproc_subdev *subdev, bool crashed)
        if (crashed)
                return;
 
+       if (sysmon->ssctl_instance) {
+               if (!wait_for_completion_timeout(&sysmon->ssctl_comp, HZ / 2))
+                       dev_err(sysmon->dev, "timeout waiting for ssctl service\n");
+       }
+
        if (sysmon->ssctl_version)
                sysmon->shutdown_acked = ssctl_request_shutdown(sysmon);
        else if (sysmon->ept)
@@ -631,6 +640,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
        init_completion(&sysmon->comp);
        init_completion(&sysmon->ind_comp);
        init_completion(&sysmon->shutdown_comp);
+       init_completion(&sysmon->ssctl_comp);
        mutex_init(&sysmon->lock);
        mutex_init(&sysmon->state_lock);