val = scale_mw ? DIV_ROUND_UP_ULL(power_limit_uw, 1000) : power_limit_uw; /* * This cast is lossless since here @req_power is certain to be within * the range [min_power_cap, max_power_cap] whose bounds are assured to * be two unsigned 32bits quantities.
*/
*norm = clamp_t(u32, val, spz->info->min_power_cap,
spz->info->max_power_cap);
*norm = rounddown(*norm, spz->info->power_cap_step);
staticint scmi_powercap_get_power_limit_uw(struct powercap_zone *pz, int cid,
u64 *power_limit_uw)
{ struct scmi_powercap_zone *spz = to_scmi_powercap_zone(pz);
u32 power; int ret;
ret = powercap_ops->cap_get(spz->ph, spz->info->id, &power); if (ret) return ret;
*power_limit_uw = power; if (spz->info->powercap_scale_mw)
*power_limit_uw *= 1000;
return 0;
}
staticvoid scmi_powercap_normalize_time(conststruct scmi_powercap_zone *spz,
u64 time_us, u32 *norm)
{ /* * This cast is lossless since here @time_us is certain to be within the * range [min_pai, max_pai] whose bounds are assured to be two unsigned * 32bits quantities.
*/
*norm = clamp_t(u32, time_us, spz->info->min_pai, spz->info->max_pai);
*norm = rounddown(*norm, spz->info->pai_step);
staticvoid scmi_powercap_unregister_all_zones(struct scmi_powercap_root *pr)
{ int i;
/* Un-register children zones first starting from the leaves */ for (i = pr->num_zones - 1; i >= 0; i--) { if (!list_empty(&pr->registered_zones[i])) { struct scmi_powercap_zone *spz;
/** * scmi_zones_register- Register SCMI powercap zones starting from parent zones * * @dev: A reference to the SCMI device * @pr: A reference to the root powercap zones descriptors * * When registering SCMI powercap zones with the powercap framework we should * take care to always register zones starting from the root ones and to * deregister starting from the leaves. * * Unfortunately we cannot assume that the array of available SCMI powercap * zones provided by the SCMI platform firmware is built to comply with such * requirement. * * This function, given the set of SCMI powercap zones to register, takes care * to walk the SCMI powercap zones trees up to the root registering any * unregistered parent zone before registering the child zones; at the same * time each registered-zone height in such a tree is accounted for and each * zone, once registered, is stored in the @registered_zones array that is * indexed by zone height: this way will be trivial, at unregister time, to walk * the @registered_zones array backward and unregister all the zones starting * from the leaves, removing children zones before parents. * * While doing this, we prune away any zone marked as invalid (like the ones * sporting an SCMI abstract power scale) as long as they are positioned as * leaves in the SCMI powercap zones hierarchy: any non-leaf invalid zone causes * the entire process to fail since we cannot assume the correctness of an SCMI * powercap zones hierarchy if some of the internal nodes are missing. * * Note that the array of SCMI powercap zones as returned by the SCMI platform * is known to be sane, i.e. zones relationships have been validated at the * protocol layer. * * Return: 0 on Success
*/ staticint scmi_zones_register(struct device *dev, struct scmi_powercap_root *pr)
{ int ret = 0; unsignedint sp = 0, reg_zones = 0; struct scmi_powercap_zone *spz, **zones_stack;
zones_stack = kcalloc(pr->num_zones, sizeof(spz), GFP_KERNEL); if (!zones_stack) return -ENOMEM;
powercap_ops = sdev->handle->devm_protocol_get(sdev,
SCMI_PROTOCOL_POWERCAP,
&ph); if (IS_ERR(powercap_ops)) return PTR_ERR(powercap_ops);
pr = devm_kzalloc(dev, sizeof(*pr), GFP_KERNEL); if (!pr) return -ENOMEM;
ret = powercap_ops->num_domains_get(ph); if (ret < 0) {
dev_err(dev, "number of powercap domains not found\n"); return ret;
}
pr->num_zones = ret;
pr->spzones = devm_kcalloc(dev, pr->num_zones, sizeof(*pr->spzones), GFP_KERNEL); if (!pr->spzones) return -ENOMEM;
/* Allocate for worst possible scenario of maximum tree height. */
pr->registered_zones = devm_kcalloc(dev, pr->num_zones, sizeof(*pr->registered_zones),
GFP_KERNEL); if (!pr->registered_zones) return -ENOMEM;
INIT_LIST_HEAD(&pr->scmi_zones);
for (i = 0, spz = pr->spzones; i < pr->num_zones; i++, spz++) { /* * Powercap domains are validate by the protocol layer, i.e. * when only non-NULL domains are returned here, whose * parent_id is assured to point to another valid domain.
*/
spz->info = powercap_ops->info_get(ph, i);
list_add_tail(&spz->node, &pr->scmi_zones); /* * Forcibly skip powercap domains using an abstract scale. * Note that only leaves domains can be skipped, so this could * lead later to a global failure.
*/ if (!spz->info->powercap_scale_uw &&
!spz->info->powercap_scale_mw) {
dev_warn(dev, "Abstract power scale not supported. Skip %s.\n",
spz->info->name);
spz->invalid = true; continue;
}
}
/* * Scan array of retrieved SCMI powercap domains and register them * recursively starting from the root domains.
*/
ret = scmi_zones_register(dev, pr); if (ret) return ret;
Die Informationen auf dieser Webseite wurden
nach bestem Wissen sorgfältig zusammengestellt. Es wird jedoch weder Vollständigkeit, noch Richtigkeit,
noch Qualität der bereit gestellten Informationen zugesichert.
Bemerkung:
Die farbliche Syntaxdarstellung und die Messung sind noch experimentell.