soc: rockchip: power-domain: Add dmcfreq lock when pd on/off

In order to 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);      ...

Change-Id: I56a4ee944200826d2a09e3ae8d2f4837f6f769d6
Signed-off-by: Finley Xiao <finley.xiao@rock-chips.com>
Signed-off-by: Elaine Zhang <zhangqing@rock-chips.com>
This commit is contained in:
Finley Xiao
2019-10-21 15:03:14 +08:00
committed by Tao Huang
parent 68b2fe5e6d
commit 9163d61374

View File

@@ -19,6 +19,7 @@
#include <linux/pm_runtime.h>
#include <linux/regulator/consumer.h>
#include <soc/rockchip/pm_domains.h>
#include <soc/rockchip/rockchip_dmc.h>
#include <dt-bindings/power/px30-power.h>
#include <dt-bindings/power/rk1808-power.h>
#include <dt-bindings/power/rk3036-power.h>
@@ -93,6 +94,18 @@ struct rockchip_pmu {
static struct rockchip_pmu *g_pmu;
static void rockchip_pmu_lock(struct rockchip_pm_domain *pd)
{
mutex_lock(&pd->pmu->mutex);
rockchip_dmcfreq_lock_nested();
}
static void rockchip_pmu_unlock(struct rockchip_pm_domain *pd)
{
rockchip_dmcfreq_unlock();
mutex_unlock(&pd->pmu->mutex);
}
#define to_rockchip_pd(gpd) container_of(gpd, struct rockchip_pm_domain, genpd)
#define DOMAIN(pwr, status, req, idle, ack, wakeup, keepon) \
@@ -238,9 +251,9 @@ int rockchip_pmu_idle_request(struct device *dev, bool idle)
genpd = pd_to_genpd(dev->pm_domain);
pd = to_rockchip_pd(genpd);
mutex_lock(&pd->pmu->mutex);
rockchip_pmu_lock(pd);
ret = rockchip_pmu_set_idle_request(pd, idle);
mutex_unlock(&pd->pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
@@ -310,9 +323,9 @@ int rockchip_save_qos(struct device *dev)
genpd = pd_to_genpd(dev->pm_domain);
pd = to_rockchip_pd(genpd);
mutex_lock(&pd->pmu->mutex);
rockchip_pmu_lock(pd);
ret = rockchip_pmu_save_qos(pd);
mutex_unlock(&pd->pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
@@ -333,9 +346,9 @@ int rockchip_restore_qos(struct device *dev)
genpd = pd_to_genpd(dev->pm_domain);
pd = to_rockchip_pd(genpd);
mutex_lock(&pd->pmu->mutex);
rockchip_pmu_lock(pd);
ret = rockchip_pmu_restore_qos(pd);
mutex_unlock(&pd->pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
@@ -397,7 +410,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
int ret = 0;
struct generic_pm_domain *genpd = &pd->genpd;
mutex_lock(&pmu->mutex);
rockchip_pmu_lock(pd);
if (rockchip_pmu_domain_is_on(pd) != power_on) {
if (IS_ERR_OR_NULL(pd->supply) &&
@@ -410,7 +423,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
if (ret < 0) {
dev_err(pd->pmu->dev, "failed to set vdd supply enable '%s',\n",
genpd->name);
mutex_unlock(&pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
}
@@ -418,7 +431,7 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on)
ret = clk_bulk_enable(pd->num_clks, pd->clks);
if (ret < 0) {
dev_err(pmu->dev, "failed to enable clocks\n");
mutex_unlock(&pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
@@ -462,7 +475,7 @@ out:
ret = regulator_disable(pd->supply);
}
mutex_unlock(&pmu->mutex);
rockchip_pmu_unlock(pd);
return ret;
}
@@ -696,9 +709,9 @@ static void rockchip_pm_remove_one_domain(struct rockchip_pm_domain *pd)
clk_bulk_put(pd->num_clks, pd->clks);
/* protect the zeroing of pm->num_clks */
mutex_lock(&pd->pmu->mutex);
rockchip_pmu_lock(pd);
pd->num_clks = 0;
mutex_unlock(&pd->pmu->mutex);
rockchip_pmu_unlock(pd);
/* devm will free our memory */
}