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