static int _genpd_set_performance_state()

in power/domain.c [312:380]


static int _genpd_set_performance_state(struct generic_pm_domain *genpd,
					unsigned int state, int depth)
{
	struct generic_pm_domain *parent;
	struct gpd_link *link;
	int parent_state, ret;

	if (state == genpd->performance_state)
		return 0;

	/* Propagate to parents of genpd */
	list_for_each_entry(link, &genpd->child_links, child_node) {
		parent = link->parent;

		/* Find parent's performance state */
		ret = genpd_xlate_performance_state(genpd, parent, state);
		if (unlikely(ret < 0))
			goto err;

		parent_state = ret;

		genpd_lock_nested(parent, depth + 1);

		link->prev_performance_state = link->performance_state;
		link->performance_state = parent_state;
		parent_state = _genpd_reeval_performance_state(parent,
						parent_state);
		ret = _genpd_set_performance_state(parent, parent_state, depth + 1);
		if (ret)
			link->performance_state = link->prev_performance_state;

		genpd_unlock(parent);

		if (ret)
			goto err;
	}

	if (genpd->set_performance_state) {
		ret = genpd->set_performance_state(genpd, state);
		if (ret)
			goto err;
	}

	genpd->performance_state = state;
	return 0;

err:
	/* Encountered an error, lets rollback */
	list_for_each_entry_continue_reverse(link, &genpd->child_links,
					     child_node) {
		parent = link->parent;

		genpd_lock_nested(parent, depth + 1);

		parent_state = link->prev_performance_state;
		link->performance_state = parent_state;

		parent_state = _genpd_reeval_performance_state(parent,
						parent_state);
		if (_genpd_set_performance_state(parent, parent_state, depth + 1)) {
			pr_err("%s: Failed to roll back to %d performance state\n",
			       parent->name, parent_state);
		}

		genpd_unlock(parent);
	}

	return ret;
}