summaryrefslogtreecommitdiff
path: root/drivers/devfreq
diff options
context:
space:
mode:
authorTao Huang <huangtao@rock-chips.com>2018-05-16 17:01:32 +0800
committerTao Huang <huangtao@rock-chips.com>2018-05-17 11:43:55 +0800
commitc95036feef0459dcd5b6af1ad7a30f30cc1d03ed (patch)
tree079c099e5d3dca9a4ef685e3638f4cb859df5025 /drivers/devfreq
parent48b41d013e973a15f9b174dbb68ae69c5941cdd5 (diff)
PM / devfreq: rockchip_dmc: Fix deadlock between dmcfreq and vop on/off
When change vop status and ddr frequency at the same time, the following deadlock will happen: vop no/off dmcfreq vop_crtc_disable update_devfreq ->mutex_lock(&vop->vop_lock); ->mutex_lock(&pd->pmu->mutex); ->pm_runtime_put(vop->dev); ->mutex_lock(&vop->vop_lock); ->mutex_lock(&pd->pmu->mutex); ... Use new dmcfreq rwsem to decouple vop and pd driver, and get better parallelism. Change-Id: I56a4ee944200826d2a09e3ae8d2f4837f6f769d6 Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com> Signed-off-by: Tao Huang <huangtao@rock-chips.com>
Diffstat (limited to 'drivers/devfreq')
-rw-r--r--drivers/devfreq/rockchip_dmc.c30
1 files changed, 24 insertions, 6 deletions
diff --git a/drivers/devfreq/rockchip_dmc.c b/drivers/devfreq/rockchip_dmc.c
index cfef9aabc97e..476b2cba0606 100644
--- a/drivers/devfreq/rockchip_dmc.c
+++ b/drivers/devfreq/rockchip_dmc.c
@@ -812,6 +812,20 @@ struct rockchip_dmcfreq {
static struct pm_qos_request pm_qos;
+static DECLARE_RWSEM(rockchip_dmcfreq_sem);
+
+void rockchip_dmcfreq_lock(void)
+{
+ down_read(&rockchip_dmcfreq_sem);
+}
+EXPORT_SYMBOL(rockchip_dmcfreq_lock);
+
+void rockchip_dmcfreq_unlock(void)
+{
+ up_read(&rockchip_dmcfreq_sem);
+}
+EXPORT_SYMBOL(rockchip_dmcfreq_unlock);
+
/*
* function: packaging de-skew setting to px30_ddr_dts_config_timing,
* px30_ddr_dts_config_timing will pass to trust firmware, and
@@ -1016,8 +1030,18 @@ static int rockchip_dmcfreq_target(struct device *dev, unsigned long *freq,
}
}
+ /*
+ * Writer in rwsem may block readers even during its waiting in queue,
+ * and this may lead to a deadlock when the code path takes read sem
+ * twice (e.g. one in vop_lock() and another in rockchip_pmu_lock()).
+ * As a (suboptimal) workaround, let writer to spin until it gets the
+ * lock.
+ */
+ while (!down_write_trylock(&rockchip_dmcfreq_sem))
+ cond_resched();
dev_dbg(dev, "%lu-->%lu\n", old_clk_rate, target_rate);
err = clk_set_rate(dmcfreq->dmc_clk, target_rate);
+ up_write(&rockchip_dmcfreq_sem);
if (err) {
dev_err(dev, "Cannot set frequency %lu (%d)\n",
target_rate, err);
@@ -3060,12 +3084,6 @@ static int rockchip_dmcfreq_probe(struct platform_device *pdev)
data->devfreq->last_status.current_frequency = opp_rate;
reset_last_status(data->devfreq);
- if (rockchip_drm_register_notifier_to_dmc(data->devfreq))
- dev_err(dev, "drm fail to register notifier to dmc\n");
-
- if (rockchip_pm_register_notify_to_dmc(data->devfreq))
- dev_err(dev, "pd fail to register notify to dmc\n");
-
if (vop_register_dmc())
dev_err(dev, "fail to register notify to vop.\n");