/* Power zone show function */ #define define_power_zone_show(_attr) \ static ssize_t _attr##_show(struct device *dev, \ struct device_attribute *dev_attr,\ char *buf) \
{ \
u64 value; \
ssize_t len = -EINVAL; \ struct powercap_zone *power_zone = to_powercap_zone(dev); \
\ if (power_zone->ops->get_##_attr) { \ if (!power_zone->ops->get_##_attr(power_zone, &value)) \
len = sprintf(buf, "%lld\n", value); \
} \
\ return len; \
}
/* The only meaningful input is 0 (reset), others are silently ignored */ #define define_power_zone_store(_attr) \ static ssize_t _attr##_store(struct device *dev,\ struct device_attribute *dev_attr, \ constchar *buf, size_t count) \
{ \ int err; \ struct powercap_zone *power_zone = to_powercap_zone(dev); \
u64 value; \
\
err = kstrtoull(buf, 10, &value); \ if (err) \ return -EINVAL; \ if (value) \ return count; \ if (power_zone->ops->reset_##_attr) { \ if (!power_zone->ops->reset_##_attr(power_zone)) \ return count; \
} \
\ return -EINVAL; \
}
/* Power zone constraint show function */ #define define_power_zone_constraint_show(_attr) \ static ssize_t show_constraint_##_attr(struct device *dev, \ struct device_attribute *dev_attr,\ char *buf) \
{ \
u64 value; \
ssize_t len = -ENODATA; \ struct powercap_zone *power_zone = to_powercap_zone(dev); \ int id; \ struct powercap_zone_constraint *pconst;\
\ if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ return -EINVAL; \ if (id >= power_zone->const_id_cnt) \ return -EINVAL; \
pconst = &power_zone->constraints[id]; \ if (pconst && pconst->ops && pconst->ops->get_##_attr) { \ if (!pconst->ops->get_##_attr(power_zone, id, &value)) \
len = sprintf(buf, "%lld\n", value); \
} \
\ return len; \
}
/* Power zone constraint store function */ #define define_power_zone_constraint_store(_attr) \ static ssize_t store_constraint_##_attr(struct device *dev,\ struct device_attribute *dev_attr, \ constchar *buf, size_t count) \
{ \ int err; \
u64 value; \ struct powercap_zone *power_zone = to_powercap_zone(dev); \ int id; \ struct powercap_zone_constraint *pconst;\
\ if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ return -EINVAL; \ if (id >= power_zone->const_id_cnt) \ return -EINVAL; \
pconst = &power_zone->constraints[id]; \
err = kstrtoull(buf, 10, &value); \ if (err) \ return -EINVAL; \ if (pconst && pconst->ops && pconst->ops->set_##_attr) { \ if (!pconst->ops->set_##_attr(power_zone, id, value)) \ return count; \
} \
\ return -ENODATA; \
}
/* Power zone information callbacks */
define_power_zone_show(power_uw);
define_power_zone_show(max_power_range_uw);
define_power_zone_show(energy_uj);
define_power_zone_store(energy_uj);
define_power_zone_show(max_energy_range_uj);
/* Power zone attributes */ static DEVICE_ATTR_RO(max_power_range_uw); static DEVICE_ATTR_RO(power_uw); static DEVICE_ATTR_RO(max_energy_range_uj); static DEVICE_ATTR_RW(energy_uj);
/* Power zone constraint attributes callbacks */
define_power_zone_constraint_show(power_limit_uw);
define_power_zone_constraint_store(power_limit_uw);
define_power_zone_constraint_show(time_window_us);
define_power_zone_constraint_store(time_window_us);
define_power_zone_constraint_show(max_power_uw);
define_power_zone_constraint_show(min_power_uw);
define_power_zone_constraint_show(max_time_window_us);
define_power_zone_constraint_show(min_time_window_us);
/* For one time seeding of constraint device attributes */ struct powercap_constraint_attr { struct device_attribute power_limit_attr; struct device_attribute time_window_attr; struct device_attribute max_power_attr; struct device_attribute min_power_attr; struct device_attribute max_time_window_attr; struct device_attribute min_time_window_attr; struct device_attribute name_attr;
};
/* A list of powercap control_types */ static LIST_HEAD(powercap_cntrl_list); /* Mutex to protect list of powercap control_types */ static DEFINE_MUTEX(powercap_cntrl_list_lock);
#define POWERCAP_CONSTRAINT_NAME_LEN 30 /* Some limit to avoid overflow */ static ssize_t show_constraint_name(struct device *dev, struct device_attribute *dev_attr, char *buf)
{ constchar *name; struct powercap_zone *power_zone = to_powercap_zone(dev); int id;
ssize_t len = -ENODATA; struct powercap_zone_constraint *pconst;
if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) return -EINVAL; if (id >= power_zone->const_id_cnt) return -EINVAL;
pconst = &power_zone->constraints[id];
if (pconst && pconst->ops && pconst->ops->get_name) {
name = pconst->ops->get_name(power_zone, id); if (name) {
sprintf(buf, "%.*s\n", POWERCAP_CONSTRAINT_NAME_LEN - 1,
name);
len = strlen(buf);
}
}
staticvoid free_constraint_attributes(void)
{ int i;
for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
kfree(constraint_attrs[i].power_limit_attr.attr.name);
kfree(constraint_attrs[i].time_window_attr.attr.name);
kfree(constraint_attrs[i].name_attr.attr.name);
kfree(constraint_attrs[i].max_power_attr.attr.name);
kfree(constraint_attrs[i].min_power_attr.attr.name);
kfree(constraint_attrs[i].max_time_window_attr.attr.name);
kfree(constraint_attrs[i].min_time_window_attr.attr.name);
}
}
staticint seed_constraint_attributes(void)
{ int i; int ret;
for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) {
ret = create_constraint_attribute(i, "power_limit_uw",
S_IWUSR | S_IRUGO,
&constraint_attrs[i].power_limit_attr,
show_constraint_power_limit_uw,
store_constraint_power_limit_uw); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "time_window_us",
S_IWUSR | S_IRUGO,
&constraint_attrs[i].time_window_attr,
show_constraint_time_window_us,
store_constraint_time_window_us); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "name", S_IRUGO,
&constraint_attrs[i].name_attr,
show_constraint_name,
NULL); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO,
&constraint_attrs[i].max_power_attr,
show_constraint_max_power_uw,
NULL); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO,
&constraint_attrs[i].min_power_attr,
show_constraint_min_power_uw,
NULL); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "max_time_window_us",
S_IRUGO,
&constraint_attrs[i].max_time_window_attr,
show_constraint_max_time_window_us,
NULL); if (ret) goto err_alloc;
ret = create_constraint_attribute(i, "min_time_window_us",
S_IRUGO,
&constraint_attrs[i].min_time_window_attr,
show_constraint_min_time_window_us,
NULL); if (ret) goto err_alloc;
}
return 0;
err_alloc:
free_constraint_attributes();
return ret;
}
staticint create_constraints(struct powercap_zone *power_zone, int nr_constraints, conststruct powercap_zone_constraint_ops *const_ops)
{ int i; int ret = 0; int count; struct powercap_zone_constraint *pconst;
if (dev->parent) { struct powercap_zone *power_zone = to_powercap_zone(dev);
/* Store flag as the release() may free memory */
allocated = power_zone->allocated; /* Remove id from parent idr struct */
idr_remove(power_zone->parent_idr, power_zone->id); /* Destroy idrs allocated for this zone */
idr_destroy(&power_zone->idr);
kfree(power_zone->name);
kfree(power_zone->zone_dev_attrs);
kfree(power_zone->constraints); if (power_zone->ops->release)
power_zone->ops->release(power_zone); if (allocated)
kfree(power_zone);
} else { struct powercap_control_type *control_type =
to_powercap_control_type(dev);
/* Store flag as the release() may free memory */
allocated = control_type->allocated;
idr_destroy(&control_type->idr);
mutex_destroy(&control_type->lock); if (control_type->ops && control_type->ops->release)
control_type->ops->release(control_type); if (allocated)
kfree(control_type);
}
}
mutex_lock(&control_type->lock); /* Using idr to get the unique id */
result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL); if (result < 0) goto err_idr_alloc;
power_zone->id = result;
idr_init(&power_zone->idr);
result = -ENOMEM;
power_zone->name = kstrdup(name, GFP_KERNEL); if (!power_zone->name) goto err_name_alloc;
power_zone->constraints = kcalloc(nr_constraints, sizeof(*power_zone->constraints),
GFP_KERNEL); if (!power_zone->constraints) goto err_const_alloc;
nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS +
POWERCAP_ZONE_MAX_ATTRS + 1;
power_zone->zone_dev_attrs = kcalloc(nr_attrs, sizeof(void *),
GFP_KERNEL); if (!power_zone->zone_dev_attrs) goto err_attr_alloc;
create_power_zone_common_attributes(power_zone);
result = create_constraints(power_zone, nr_constraints, const_ops); if (result) goto err_dev_ret;
int powercap_unregister_control_type(struct powercap_control_type *control_type)
{ struct powercap_control_type *pos = NULL;
if (control_type->nr_zones) {
dev_err(&control_type->dev, "Zones of this type still not freed\n"); return -EINVAL;
}
mutex_lock(&powercap_cntrl_list_lock);
list_for_each_entry(pos, &powercap_cntrl_list, node) { if (pos == control_type) {
list_del(&control_type->node);
mutex_unlock(&powercap_cntrl_list_lock);
device_unregister(&control_type->dev); return 0;
}
}
mutex_unlock(&powercap_cntrl_list_lock);
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.