in core.c [885:940]
static int _set_required_opps(struct device *dev,
struct opp_table *opp_table,
struct dev_pm_opp *opp, bool up)
{
struct opp_table **required_opp_tables = opp_table->required_opp_tables;
struct device **genpd_virt_devs = opp_table->genpd_virt_devs;
int i, ret = 0;
if (!required_opp_tables)
return 0;
/* required-opps not fully initialized yet */
if (lazy_linking_pending(opp_table))
return -EBUSY;
/*
* We only support genpd's OPPs in the "required-opps" for now, as we
* don't know much about other use cases. Error out if the required OPP
* doesn't belong to a genpd.
*/
if (unlikely(!required_opp_tables[0]->is_genpd)) {
dev_err(dev, "required-opps don't belong to a genpd\n");
return -ENOENT;
}
/* Single genpd case */
if (!genpd_virt_devs)
return _set_required_opp(dev, dev, opp, 0);
/* Multiple genpd case */
/*
* Acquire genpd_virt_dev_lock to make sure we don't use a genpd_dev
* after it is freed from another thread.
*/
mutex_lock(&opp_table->genpd_virt_dev_lock);
/* Scaling up? Set required OPPs in normal order, else reverse */
if (up) {
for (i = 0; i < opp_table->required_opp_count; i++) {
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
if (ret)
break;
}
} else {
for (i = opp_table->required_opp_count - 1; i >= 0; i--) {
ret = _set_required_opp(dev, genpd_virt_devs[i], opp, i);
if (ret)
break;
}
}
mutex_unlock(&opp_table->genpd_virt_dev_lock);
return ret;
}