From 7466fd9c13c6de08f2de1bc69fce207d8a213022 Mon Sep 17 00:00:00 2001 From: Lina Iyer Date: Fri, 15 May 2020 15:47:46 -0600 Subject: [PATCH] soc: qcom: rpmh-rsc: Attach RSC to CPU cluster PM domain RSC is part the CPU subsystem and powers off the CPU domains when all the CPUs and no RPMH transactions are pending from any of the drivers. The RSC needs to flush the 'sleep' and 'wake' votes that are critical for saving power when all the CPUs are in idle. Doing this every time a CPU powers down, increases latency to enter idle state. So, we want to do this, only when it makes sense - when the last CPU is powering down. Let's make RSC part of the CPU PM domains, by attaching it to the cluster PD (defined in DT). Registering for PM domain notifications, RSC driver can be notified that the last CPU is powering down. When the last CPU is powering down the domain, let's flush the 'sleep' and 'wake' votes that are stored in the data buffers into the hardware. Change-Id: Id748413f0f86a4ac73c37e0780b2b22a143a1e61 Signed-off-by: Lina Iyer Signed-off-by: Maulik Shah --- drivers/soc/qcom/rpmh-internal.h | 4 ++++ drivers/soc/qcom/rpmh-rsc.c | 38 +++++++++++++++++++++++++++++++- 2 files changed, 41 insertions(+), 1 deletion(-) diff --git a/drivers/soc/qcom/rpmh-internal.h b/drivers/soc/qcom/rpmh-internal.h index 54c1e014f17f..02ad7da2e75e 100644 --- a/drivers/soc/qcom/rpmh-internal.h +++ b/drivers/soc/qcom/rpmh-internal.h @@ -119,6 +119,8 @@ struct rpmh_ctrlr { * @tcs_wait: Wait queue used to wait for @tcs_in_use to free up a * slot * @client: Handle to the DRV's client. + * @genpd_nb: PM Domain notifier + * @dev: RSC device */ struct rsc_drv { const char *name; @@ -134,6 +136,8 @@ struct rsc_drv { spinlock_t lock; wait_queue_head_t tcs_wait; struct rpmh_ctrlr client; + struct notifier_block genpd_nb; + struct device *dev; }; extern bool rpmh_standalone; diff --git a/drivers/soc/qcom/rpmh-rsc.c b/drivers/soc/qcom/rpmh-rsc.c index cf561f09bc3e..0f6b55ea426a 100644 --- a/drivers/soc/qcom/rpmh-rsc.c +++ b/drivers/soc/qcom/rpmh-rsc.c @@ -14,10 +14,13 @@ #include #include #include +#include #include #include #include #include +#include +#include #include #include #include @@ -1054,6 +1057,32 @@ static int rpmh_probe_tcs_config(struct platform_device *pdev, return 0; } +static int rpmh_rsc_pd_cb(struct notifier_block *nb, + unsigned long action, void *data) +{ + struct rsc_drv *drv = container_of(nb, struct rsc_drv, genpd_nb); + + /* We don't need to lock as domin on/off are serialized */ + if ((action == GENPD_NOTIFY_PRE_OFF) && + (rpmh_rsc_ctrlr_is_busy(drv) || rpmh_flush(&drv->client))) + return NOTIFY_BAD; + + return NOTIFY_OK; +} + +static int rpmh_rsc_pd_attach(struct rsc_drv *drv) +{ + int ret; + + pm_runtime_enable(drv->dev); + ret = dev_pm_domain_attach(drv->dev, false); + if (ret) + return ret; + + drv->genpd_nb.notifier_call = rpmh_rsc_pd_cb; + return dev_pm_genpd_add_notifier(drv->dev, &drv->genpd_nb); +} + static int rpmh_rsc_probe(struct platform_device *pdev) { struct device_node *dn = pdev->dev.of_node; @@ -1117,6 +1146,7 @@ static int rpmh_rsc_probe(struct platform_device *pdev) if (ret) return ret; + drv->dev = &pdev->dev; /* * CPU PM notification are not required for controllers that support * 'HW solver' mode where they can be in autonomous mode executing low @@ -1125,7 +1155,13 @@ static int rpmh_rsc_probe(struct platform_device *pdev) solver_config = readl_relaxed(base + DRV_SOLVER_CONFIG); solver_config &= DRV_HW_SOLVER_MASK << DRV_HW_SOLVER_SHIFT; solver_config = solver_config >> DRV_HW_SOLVER_SHIFT; - if (!solver_config) { + if (of_find_property(dn, "power-domains", NULL)) { + ret = rpmh_rsc_pd_attach(drv); + if (ret == -EPROBE_DEFER) { + pr_err("Failed to attach RSC %s to domain ret=%d\n", drv->name, ret); + return ret; + } + } else if (!solver_config) { drv->rsc_pm.notifier_call = rpmh_rsc_cpu_pm_callback; cpu_pm_register_notifier(&drv->rsc_pm); drv->client.flags &= ~SOLVER_PRESENT;