diff options
author | Tao Huang <huangtao@rock-chips.com> | 2018-05-16 17:01:32 +0800 |
---|---|---|
committer | Tao Huang <huangtao@rock-chips.com> | 2018-05-17 11:43:55 +0800 |
commit | c95036feef0459dcd5b6af1ad7a30f30cc1d03ed (patch) | |
tree | 079c099e5d3dca9a4ef685e3638f4cb859df5025 /drivers/devfreq | |
parent | 48b41d013e973a15f9b174dbb68ae69c5941cdd5 (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.c | 30 |
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"); |