diff options
author | 2025-02-20 19:58:06 +0100 | |
---|---|---|
committer | 2025-02-28 13:04:50 +0100 | |
commit | 7ab6c930b92378ab86ed05bbe78877ef578c7fea (patch) | |
tree | fcc504638251d6df93e2cb0ca6425aa2f8a08fb5 | |
parent | pmdomain: rockchip: cleanup mutex handling in rockchip_pd_power (diff) | |
download | wireguard-linux-7ab6c930b92378ab86ed05bbe78877ef578c7fea.tar.xz wireguard-linux-7ab6c930b92378ab86ed05bbe78877ef578c7fea.zip |
pmdomain: rockchip: forward rockchip_do_pmu_set_power_domain errors
Currently rockchip_do_pmu_set_power_domain prints a warning if there
have been errors turning on the power domain, but it does not return
any errors and rockchip_pd_power() tries to continue setting up the
QOS registers. This usually results in accessing unpowered registers,
which triggers an SError and a full system hang.
This improves the error handling by forwarding the error to avoid
kernel panics.
Reviewed-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Heiko Stuebner <heiko@sntech.de>
Tested-by: Adrian Larumbe <adrian.larumbe@collabora.com> # On Rock 5B
Signed-off-by: Sebastian Reichel <sebastian.reichel@collabora.com>
Link: https://lore.kernel.org/r/20250220-rk3588-gpu-pwr-domain-regulator-v6-3-a4f9c24e5b81@kernel.org
[Ulf: Fixed conflict when applying]
Signed-off-by: Ulf Hansson <ulf.hansson@linaro.org>
-rw-r--r-- | drivers/pmdomain/rockchip/pm-domains.c | 35 |
1 files changed, 23 insertions, 12 deletions
diff --git a/drivers/pmdomain/rockchip/pm-domains.c b/drivers/pmdomain/rockchip/pm-domains.c index 8b15e57aa27f..5f03da348fe3 100644 --- a/drivers/pmdomain/rockchip/pm-domains.c +++ b/drivers/pmdomain/rockchip/pm-domains.c @@ -535,17 +535,18 @@ error: return ret; } -static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, - bool on) +static int rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, + bool on) { struct rockchip_pmu *pmu = pd->pmu; struct generic_pm_domain *genpd = &pd->genpd; u32 pd_pwr_offset = pd->info->pwr_offset; bool is_on, is_mem_on = false; struct arm_smccc_res res; + int ret; if (pd->info->pwr_mask == 0) - return; + return 0; if (on && pd->info->mem_status_mask) is_mem_on = rockchip_pmu_domain_is_mem_on(pd); @@ -560,15 +561,19 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, wmb(); - if (is_mem_on && rockchip_pmu_domain_mem_reset(pd)) - return; + if (is_mem_on) { + ret = rockchip_pmu_domain_mem_reset(pd); + if (ret) + return ret; + } + - if (readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, - is_on == on, 0, 10000)) { - dev_err(pmu->dev, - "failed to set domain '%s', val=%d\n", - genpd->name, is_on); - return; + ret = readx_poll_timeout_atomic(rockchip_pmu_domain_is_on, pd, is_on, + is_on == on, 0, 10000); + if (ret) { + dev_err(pmu->dev, "failed to set domain '%s' %s, val=%d\n", + genpd->name, on ? "on" : "off", is_on); + return ret; } /* Inform firmware to keep this pd on or off */ @@ -576,6 +581,8 @@ static void rockchip_do_pmu_set_power_domain(struct rockchip_pm_domain *pd, arm_smccc_smc(ROCKCHIP_SIP_SUSPEND_MODE, ROCKCHIP_SLEEP_PD_CONFIG, pmu->info->pwr_offset + pd_pwr_offset, pd->info->pwr_mask, on, 0, 0, 0, &res); + + return 0; } static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) @@ -601,7 +608,11 @@ static int rockchip_pd_power(struct rockchip_pm_domain *pd, bool power_on) rockchip_pmu_set_idle_request(pd, true); } - rockchip_do_pmu_set_power_domain(pd, power_on); + ret = rockchip_do_pmu_set_power_domain(pd, power_on); + if (ret < 0) { + clk_bulk_disable(pd->num_clks, pd->clks); + return ret; + } if (power_on) { /* if powering up, leave idle mode */ |