]> git.ipfire.org Git - thirdparty/kernel/linux.git/commitdiff
pmdomain: rockchip: forward rockchip_do_pmu_set_power_domain errors
authorSebastian Reichel <sebastian.reichel@collabora.com>
Thu, 20 Feb 2025 18:58:06 +0000 (19:58 +0100)
committerUlf Hansson <ulf.hansson@linaro.org>
Fri, 28 Feb 2025 12:04:50 +0000 (13:04 +0100)
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>
drivers/pmdomain/rockchip/pm-domains.c

index 8b15e57aa27fe38556cd5ae5a578996721a9b4ef..5f03da348fe39cdf468e44ca7eafb0209a4875fc 100644 (file)
@@ -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 */