clk: qcom: gdsc: Capture pm_genpd_add_subdomain result code
authorBryan O'Donoghue <bryan.odonoghue@linaro.org>
Fri, 17 Jan 2025 13:54:08 +0000 (13:54 +0000)
committerGreg Kroah-Hartman <gregkh@linuxfoundation.org>
Fri, 25 Apr 2025 08:45:33 +0000 (10:45 +0200)
commit 65a733464553ea192797b889d1533a1a37216f32 upstream.

Adding a new clause to this if/else I noticed the existing usage of
pm_genpd_add_subdomain() wasn't capturing and returning the result code.

pm_genpd_add_subdomain() returns an int and can fail. Capture that result
code and throw it up the call stack if something goes wrong.

Fixes: 1b771839de05 ("clk: qcom: gdsc: enable optional power domain support")
Cc: stable@vger.kernel.org
Signed-off-by: Bryan O'Donoghue <bryan.odonoghue@linaro.org>
Link: https://lore.kernel.org/r/20250117-b4-linux-next-24-11-18-clock-multiple-power-domains-v10-2-13f2bb656dad@linaro.org
Signed-off-by: Bjorn Andersson <andersson@kernel.org>
Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
drivers/clk/qcom/gdsc.c

index 50926ddeedfd92babefb59ae65963752327f6c94..361741f3e24395c8e1ee6a23fceddb75ece0284e 100644 (file)
@@ -465,6 +465,23 @@ err_disable_supply:
        return ret;
 }
 
+static void gdsc_pm_subdomain_remove(struct gdsc_desc *desc, size_t num)
+{
+       struct device *dev = desc->dev;
+       struct gdsc **scs = desc->scs;
+       int i;
+
+       /* Remove subdomains */
+       for (i = num - 1; i >= 0; i--) {
+               if (!scs[i])
+                       continue;
+               if (scs[i]->parent)
+                       pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd);
+               else if (!IS_ERR_OR_NULL(dev->pm_domain))
+                       pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+       }
+}
+
 int gdsc_register(struct gdsc_desc *desc,
                  struct reset_controller_dev *rcdev, struct regmap *regmap)
 {
@@ -509,30 +526,27 @@ int gdsc_register(struct gdsc_desc *desc,
                if (!scs[i])
                        continue;
                if (scs[i]->parent)
-                       pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd);
+                       ret = pm_genpd_add_subdomain(scs[i]->parent, &scs[i]->pd);
                else if (!IS_ERR_OR_NULL(dev->pm_domain))
-                       pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+                       ret = pm_genpd_add_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
+               if (ret)
+                       goto err_pm_subdomain_remove;
        }
 
        return of_genpd_add_provider_onecell(dev->of_node, data);
+
+err_pm_subdomain_remove:
+       gdsc_pm_subdomain_remove(desc, i);
+
+       return ret;
 }
 
 void gdsc_unregister(struct gdsc_desc *desc)
 {
-       int i;
        struct device *dev = desc->dev;
-       struct gdsc **scs = desc->scs;
        size_t num = desc->num;
 
-       /* Remove subdomains */
-       for (i = num - 1; i >= 0; i--) {
-               if (!scs[i])
-                       continue;
-               if (scs[i]->parent)
-                       pm_genpd_remove_subdomain(scs[i]->parent, &scs[i]->pd);
-               else if (!IS_ERR_OR_NULL(dev->pm_domain))
-                       pm_genpd_remove_subdomain(pd_to_genpd(dev->pm_domain), &scs[i]->pd);
-       }
+       gdsc_pm_subdomain_remove(desc, num);
        of_genpd_del_provider(dev->of_node);
 }