@@ -7,6 +7,7 @@
#include <linux/soc/qcom/qmi.h>
struct qcom_sysmon;
+struct qcom_q6v5;
struct qcom_rproc_glink {
struct rproc_subdev subdev;
@@ -45,12 +46,14 @@ void qcom_remove_ssr_subdev(struct rproc *rproc, struct qcom_rproc_ssr *ssr);
#if IS_ENABLED(CONFIG_QCOM_SYSMON)
struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
- int ssctl_instance);
+ int ssctl_instance,
+ struct qcom_q6v5 *q6v5);
void qcom_remove_sysmon_subdev(struct qcom_sysmon *sysmon);
#else
static inline struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
- int ssctl_instance)
+ int ssctl_instance,
+ struct qcom_q6v5 *q6v5)
{
return NULL;
}
@@ -25,6 +25,7 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5)
{
reinit_completion(&q6v5->start_done);
reinit_completion(&q6v5->stop_done);
+ reinit_completion(&q6v5->shutdown_done);
q6v5->running = true;
q6v5->handover_issued = false;
@@ -141,6 +142,35 @@ static irqreturn_t q6v5_stop_interrupt(int irq, void *data)
return IRQ_HANDLED;
}
+static irqreturn_t q6v5_shutdown_interrupt(int irq, void *data)
+{
+ struct qcom_q6v5 *q6v5 = data;
+
+ complete(&q6v5->shutdown_done);
+
+ return IRQ_HANDLED;
+}
+
+/**
+ * qcom_q6v5_wait_for_shutdown() - wait for remote processor shutdown signal
+ * @q6v5: reference to qcom_q6v5 context
+ * @timeout: timeout to wait for the event, in jiffies
+ *
+ * Return: 0 on success, -ETIMEDOUT on timeout
+ */
+int qcom_q6v5_wait_for_shutdown(struct qcom_q6v5 *q6v5, int timeout)
+{
+ int ret;
+
+ if (!q6v5->has_shutdown_irq)
+ return 0;
+
+ ret = wait_for_completion_timeout(&q6v5->shutdown_done, timeout);
+
+ return !ret ? -ETIMEDOUT : 0;
+}
+EXPORT_SYMBOL_GPL(qcom_q6v5_wait_for_shutdown);
+
/**
* qcom_q6v5_request_stop() - request the remote processor to stop
* @q6v5: reference to qcom_q6v5 context
@@ -185,6 +215,7 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
init_completion(&q6v5->start_done);
init_completion(&q6v5->stop_done);
+ init_completion(&q6v5->shutdown_done);
q6v5->wdog_irq = platform_get_irq_byname(pdev, "wdog");
if (q6v5->wdog_irq < 0) {
@@ -277,6 +308,28 @@ int qcom_q6v5_init(struct qcom_q6v5 *q6v5, struct platform_device *pdev,
return ret;
}
+ if (q6v5->has_shutdown_irq) {
+ q6v5->shutdown_irq = platform_get_irq_byname(pdev,
+ "shutdown-ack");
+ if (q6v5->shutdown_irq < 0) {
+ if (q6v5->shutdown_irq != -EPROBE_DEFER)
+ dev_err(&pdev->dev,
+ "failed to get shutdown-ack IRQ: %d\n",
+ q6v5->shutdown_irq);
+ return q6v5->shutdown_irq;
+ }
+
+ ret = devm_request_threaded_irq(&pdev->dev, q6v5->shutdown_irq,
+ NULL, q6v5_shutdown_interrupt,
+ IRQF_TRIGGER_RISING |
+ IRQF_ONESHOT,
+ "q6v5 shutdown", q6v5);
+ if (ret) {
+ dev_err(&pdev->dev, "failed to acquire shutdown IRQ\n");
+ return ret;
+ }
+ }
+
q6v5->state = qcom_smem_state_get(&pdev->dev, "stop", &q6v5->stop_bit);
if (IS_ERR(q6v5->state)) {
dev_err(&pdev->dev, "failed to acquire stop state\n");
@@ -21,11 +21,15 @@ struct qcom_q6v5 {
int ready_irq;
int handover_irq;
int stop_irq;
+ int shutdown_irq;
+
+ u8 has_shutdown_irq;
bool handover_issued;
struct completion start_done;
struct completion stop_done;
+ struct completion shutdown_done;
int crash_reason;
@@ -42,5 +46,6 @@ int qcom_q6v5_prepare(struct qcom_q6v5 *q6v5);
int qcom_q6v5_unprepare(struct qcom_q6v5 *q6v5);
int qcom_q6v5_request_stop(struct qcom_q6v5 *q6v5);
int qcom_q6v5_wait_for_start(struct qcom_q6v5 *q6v5, int timeout);
+int qcom_q6v5_wait_for_shutdown(struct qcom_q6v5 *q6v5, int timeout);
#endif
@@ -438,7 +438,8 @@ static int adsp_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
- desc->ssctl_id);
+ desc->ssctl_id,
+ &adsp->q6v5);
ret = rproc_add(rproc);
if (ret)
@@ -1340,7 +1340,8 @@ static int q6v5_probe(struct platform_device *pdev)
qcom_add_glink_subdev(rproc, &qproc->glink_subdev);
qcom_add_smd_subdev(rproc, &qproc->smd_subdev);
qcom_add_ssr_subdev(rproc, &qproc->ssr_subdev, "mpss");
- qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12);
+ qproc->sysmon = qcom_add_sysmon_subdev(rproc, "modem", 0x12,
+ &qproc->q6v5);
ret = rproc_add(rproc);
if (ret)
@@ -303,7 +303,8 @@ static int adsp_probe(struct platform_device *pdev)
qcom_add_ssr_subdev(rproc, &adsp->ssr_subdev, desc->ssr_name);
adsp->sysmon = qcom_add_sysmon_subdev(rproc,
desc->sysmon_name,
- desc->ssctl_id);
+ desc->ssctl_id,
+ &adsp->q6v5);
ret = rproc_add(rproc);
if (ret)
@@ -14,12 +14,14 @@
#include <linux/rpmsg.h>
#include "qcom_common.h"
+#include "qcom_q6v5.h"
static BLOCKING_NOTIFIER_HEAD(sysmon_notifiers);
struct qcom_sysmon {
struct rproc_subdev subdev;
struct rproc *rproc;
+ struct qcom_q6v5 *q6v5;
struct list_head node;
@@ -442,7 +444,8 @@ static int sysmon_notify(struct notifier_block *nb, unsigned long event,
*/
struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
const char *name,
- int ssctl_instance)
+ int ssctl_instance,
+ struct qcom_q6v5 *q6v5)
{
struct qcom_sysmon *sysmon;
int ret;
@@ -456,6 +459,7 @@ struct qcom_sysmon *qcom_add_sysmon_subdev(struct rproc *rproc,
sysmon->name = name;
sysmon->ssctl_instance = ssctl_instance;
+ sysmon->q6v5 = q6v5;
init_completion(&sysmon->comp);
mutex_init(&sysmon->lock);
@@ -552,7 +552,8 @@ static int wcnss_probe(struct platform_device *pdev)
}
qcom_add_smd_subdev(rproc, &wcnss->smd_subdev);
- wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID);
+ wcnss->sysmon = qcom_add_sysmon_subdev(rproc, "wcnss", WCNSS_SSCTL_ID,
+ NULL);
ret = rproc_add(rproc);
if (ret)
Add shutdown-ack irq handling for Q6V5. This patch includes enabling shutdown-ack irq on those Q6V5 instances with "has_shutdown_irq" flag set and exposing Q6V5 state information to the sysmon instance which is required to ascertain graceful shutdown completion. Signed-off-by: Sibi Sankar <sibis@codeaurora.org> --- v2: Move shutdown-irq get to Q6V5 from sysmon to handle -EPROBE_DEFER cases Correct the shutdown-irq wait time to 10 * HZ drivers/remoteproc/qcom_common.h | 7 ++-- drivers/remoteproc/qcom_q6v5.c | 53 +++++++++++++++++++++++++++++ drivers/remoteproc/qcom_q6v5.h | 5 +++ drivers/remoteproc/qcom_q6v5_adsp.c | 3 +- drivers/remoteproc/qcom_q6v5_mss.c | 3 +- drivers/remoteproc/qcom_q6v5_pas.c | 3 +- drivers/remoteproc/qcom_sysmon.c | 6 +++- drivers/remoteproc/qcom_wcnss.c | 3 +- 8 files changed, 76 insertions(+), 7 deletions(-)