Donate to e Foundation | Murena handsets with /e/OS | Own a part of Murena! Learn more

Commit 9e08cf42 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

PM / Domains: Make pm_genpd_poweron() always survive parent removal



If pm_genpd_remove_subdomain() is called to remove a PM domain's
subdomain and pm_genpd_poweron() is called for that subdomain at
the same time, and the pm_genpd_poweron() called by it recursively
for the parent returns an error, the first pm_genpd_poweron()'s
error code path will attempt to decrement the subdomain counter of
a PM domain that it's not a subdomain of any more.

Rearrange the code in pm_genpd_poweron() to prevent this from
happening.

Signed-off-by: default avatarRafael J. Wysocki <rjw@sisk.pl>
parent 3c07cbc4
Loading
Loading
Loading
Loading
+20 −13
Original line number Diff line number Diff line
@@ -89,12 +89,14 @@ static void genpd_set_active(struct generic_pm_domain *genpd)
 */
int pm_genpd_poweron(struct generic_pm_domain *genpd)
{
	struct generic_pm_domain *parent = genpd->parent;
	struct generic_pm_domain *parent;
	int ret = 0;

 start:
	mutex_lock(&genpd->lock);

	parent = genpd->parent;

 start:
	if (genpd->status == GPD_STATE_ACTIVE
	    || (genpd->prepared_count > 0 && genpd->suspend_power_off))
		goto out;
@@ -110,29 +112,34 @@ int pm_genpd_poweron(struct generic_pm_domain *genpd)
		mutex_unlock(&genpd->lock);

		ret = pm_genpd_poweron(parent);
		if (ret) {
			genpd_sd_counter_dec(parent);
			return ret;
		}

		mutex_lock(&genpd->lock);

		if (ret)
			goto err;

		parent = NULL;
		goto start;
	}

	if (genpd->power_on)
	if (genpd->power_on) {
		ret = genpd->power_on(genpd);
		if (ret)
			goto err;
	}

	if (ret) {
		if (genpd->parent)
			genpd_sd_counter_dec(genpd->parent);
	} else {
	genpd_set_active(genpd);
	}

 out:
	mutex_unlock(&genpd->lock);

	return ret;

 err:
	if (genpd->parent)
		genpd_sd_counter_dec(genpd->parent);

	goto out;
}

#endif /* CONFIG_PM */