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;
}