[RFC PATCH v3] remoteproc: qcom: q6v5-mss: Sync MSS with RMTFS QMI service

From: Sibi Sankar
Date: Wed Oct 31 2018 - 06:46:33 EST


Introduce RMTFS qmi lookup client to synchronize bring up/down modem
with the REMOTE FS QMI service.

Signed-off-by: Sibi Sankar <sibis@xxxxxxxxxxxxxx>
---
The currently implemented workaround in the Linaro QCOMLT releases is to
blacklist the qcom_q6v5_pil kernel module and load this explicitly after rmtfs
has been started.

With this patch the modem module can be loaded automatically by the
platform_bus and will only be booted as the rmtfs becomes available. Performing
actions such as upgrading (and restarting) the rmtfs service will cause the
modem to automatically restart and hence continue to function after the
upgrade.

v3:
Move rmtfs lookup client to the q6v5_mss driver
[Suggested-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>]
[Suggested-by: Brian Norris <briannorris@xxxxxxxxxxxx>]
Add deny_sysfs_ops flag to prevent updation of state/firmware
[Suggested-by: Bjorn Andersson <bjorn.andersson@xxxxxxxxxx>]

v2:
Remove rproc_boot/shutdown from rmtfs_mem open/release and add
qmi lookup for Remote file system service to address Brian's
race concerns.

Depends on: https://patchwork.kernel.org/patch/10601325/

drivers/remoteproc/Kconfig | 1 +
drivers/remoteproc/qcom_q6v5_mss.c | 41 ++++++++++++++++++++++++++++++
2 files changed, 42 insertions(+)

diff --git a/drivers/remoteproc/Kconfig b/drivers/remoteproc/Kconfig
index 8894935583e2..5919098697ec 100644
--- a/drivers/remoteproc/Kconfig
+++ b/drivers/remoteproc/Kconfig
@@ -100,6 +100,7 @@ config QCOM_Q6V5_MSS
depends on RPMSG_QCOM_GLINK_SMEM || RPMSG_QCOM_GLINK_SMEM=n
depends on QCOM_SYSMON || QCOM_SYSMON=n
select MFD_SYSCON
+ select QCOM_QMI_HELPERS
select QCOM_Q6V5_COMMON
select QCOM_RPROC_COMMON
select QCOM_SCM
diff --git a/drivers/remoteproc/qcom_q6v5_mss.c b/drivers/remoteproc/qcom_q6v5_mss.c
index da4e496816aa..436a7fec84e9 100644
--- a/drivers/remoteproc/qcom_q6v5_mss.c
+++ b/drivers/remoteproc/qcom_q6v5_mss.c
@@ -30,6 +30,7 @@
#include <linux/remoteproc.h>
#include <linux/reset.h>
#include <linux/soc/qcom/mdt_loader.h>
+#include <linux/soc/qcom/qmi.h>
#include <linux/iopoll.h>

#include "remoteproc_internal.h"
@@ -39,6 +40,7 @@
#include <linux/qcom_scm.h>

#define MPSS_CRASH_REASON_SMEM 421
+#define REMOTEFS_QMI_SVC_ID 0xE

/* RMB Status Register Values */
#define RMB_PBL_SUCCESS 0x1
@@ -180,6 +182,7 @@ struct q6v5 {
void *mpss_region;
size_t mpss_size;

+ struct qmi_handle lookup_client;
struct qcom_rproc_glink glink_subdev;
struct qcom_rproc_subdev smd_subdev;
struct qcom_rproc_ssr ssr_subdev;
@@ -991,6 +994,25 @@ static void qcom_q6v5_dump_segment(struct rproc *rproc,
}
}

+static int rmtfs_new_server(struct qmi_handle *qmi, struct qmi_service *serv)
+{
+ struct q6v5 *qproc = container_of(qmi, struct q6v5, lookup_client);
+
+ return rproc_boot(qproc->rproc);
+};
+
+static void rmtfs_del_server(struct qmi_handle *qmi, struct qmi_service *serv)
+{
+ struct q6v5 *qproc = container_of(qmi, struct q6v5, lookup_client);
+
+ rproc_shutdown(qproc->rproc);
+};
+
+static struct qmi_ops lookup_ops = {
+ .new_server = rmtfs_new_server,
+ .del_server = rmtfs_del_server,
+};
+
static int q6v5_start(struct rproc *rproc)
{
struct q6v5 *qproc = (struct q6v5 *)rproc->priv;
@@ -1269,6 +1291,9 @@ static int q6v5_probe(struct platform_device *pdev)
return -ENOMEM;
}

+ rproc->auto_boot = false;
+ rproc->deny_sysfs_ops = true;
+
qproc = (struct q6v5 *)rproc->priv;
qproc->dev = &pdev->dev;
qproc->rproc = rproc;
@@ -1346,8 +1371,23 @@ static int q6v5_probe(struct platform_device *pdev)
if (ret)
goto free_rproc;

+ /* The modem polls for REMOTE FS QMI service for a fixed period, post
+ * which it issues a fatal error. The RMTFS lookup client handles this
+ * dependency by ensuring that the modem is brought up/down in sync with
+ * the REMOTE FS QMI SERVICE.
+ */
+ ret = qmi_handle_init(&qproc->lookup_client, 0, &lookup_ops, NULL);
+ if (ret < 0) {
+ dev_err(&pdev->dev, "Failed to initialize qmi handle.\n");
+ goto delete_rproc;
+ }
+
+ qmi_add_lookup(&qproc->lookup_client, REMOTEFS_QMI_SVC_ID, 0, 0);
+
return 0;

+delete_rproc:
+ rproc_del(rproc);
free_rproc:
rproc_free(rproc);

@@ -1358,6 +1398,7 @@ static int q6v5_remove(struct platform_device *pdev)
{
struct q6v5 *qproc = platform_get_drvdata(pdev);

+ qmi_handle_release(&qproc->lookup_client);
rproc_del(qproc->rproc);

qcom_remove_sysmon_subdev(qproc->sysmon);
--
The Qualcomm Innovation Center, Inc. is a member of the Code Aurora Forum,
a Linux Foundation Collaborative Project