1f6cc69f1SThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only 275d2364eSSrinivas Pandruvada /* 375d2364eSSrinivas Pandruvada * Power capping class 475d2364eSSrinivas Pandruvada * Copyright (c) 2013, Intel Corporation. 575d2364eSSrinivas Pandruvada */ 675d2364eSSrinivas Pandruvada 775d2364eSSrinivas Pandruvada #include <linux/module.h> 875d2364eSSrinivas Pandruvada #include <linux/device.h> 975d2364eSSrinivas Pandruvada #include <linux/err.h> 1075d2364eSSrinivas Pandruvada #include <linux/slab.h> 1175d2364eSSrinivas Pandruvada #include <linux/powercap.h> 1275d2364eSSrinivas Pandruvada 1375d2364eSSrinivas Pandruvada #define to_powercap_zone(n) container_of(n, struct powercap_zone, dev) 1475d2364eSSrinivas Pandruvada #define to_powercap_control_type(n) \ 1575d2364eSSrinivas Pandruvada container_of(n, struct powercap_control_type, dev) 1675d2364eSSrinivas Pandruvada 1775d2364eSSrinivas Pandruvada /* Power zone show function */ 1875d2364eSSrinivas Pandruvada #define define_power_zone_show(_attr) \ 1975d2364eSSrinivas Pandruvada static ssize_t _attr##_show(struct device *dev, \ 2075d2364eSSrinivas Pandruvada struct device_attribute *dev_attr,\ 2175d2364eSSrinivas Pandruvada char *buf) \ 2275d2364eSSrinivas Pandruvada { \ 2375d2364eSSrinivas Pandruvada u64 value; \ 2475d2364eSSrinivas Pandruvada ssize_t len = -EINVAL; \ 2575d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); \ 2675d2364eSSrinivas Pandruvada \ 2775d2364eSSrinivas Pandruvada if (power_zone->ops->get_##_attr) { \ 2875d2364eSSrinivas Pandruvada if (!power_zone->ops->get_##_attr(power_zone, &value)) \ 2975d2364eSSrinivas Pandruvada len = sprintf(buf, "%lld\n", value); \ 3075d2364eSSrinivas Pandruvada } \ 3175d2364eSSrinivas Pandruvada \ 3275d2364eSSrinivas Pandruvada return len; \ 3375d2364eSSrinivas Pandruvada } 3475d2364eSSrinivas Pandruvada 3575d2364eSSrinivas Pandruvada /* The only meaningful input is 0 (reset), others are silently ignored */ 3675d2364eSSrinivas Pandruvada #define define_power_zone_store(_attr) \ 3775d2364eSSrinivas Pandruvada static ssize_t _attr##_store(struct device *dev,\ 3875d2364eSSrinivas Pandruvada struct device_attribute *dev_attr, \ 3975d2364eSSrinivas Pandruvada const char *buf, size_t count) \ 4075d2364eSSrinivas Pandruvada { \ 4175d2364eSSrinivas Pandruvada int err; \ 4275d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); \ 4375d2364eSSrinivas Pandruvada u64 value; \ 4475d2364eSSrinivas Pandruvada \ 4575d2364eSSrinivas Pandruvada err = kstrtoull(buf, 10, &value); \ 4675d2364eSSrinivas Pandruvada if (err) \ 4775d2364eSSrinivas Pandruvada return -EINVAL; \ 4875d2364eSSrinivas Pandruvada if (value) \ 4975d2364eSSrinivas Pandruvada return count; \ 5075d2364eSSrinivas Pandruvada if (power_zone->ops->reset_##_attr) { \ 5175d2364eSSrinivas Pandruvada if (!power_zone->ops->reset_##_attr(power_zone)) \ 5275d2364eSSrinivas Pandruvada return count; \ 5375d2364eSSrinivas Pandruvada } \ 5475d2364eSSrinivas Pandruvada \ 5575d2364eSSrinivas Pandruvada return -EINVAL; \ 5675d2364eSSrinivas Pandruvada } 5775d2364eSSrinivas Pandruvada 5875d2364eSSrinivas Pandruvada /* Power zone constraint show function */ 5975d2364eSSrinivas Pandruvada #define define_power_zone_constraint_show(_attr) \ 6075d2364eSSrinivas Pandruvada static ssize_t show_constraint_##_attr(struct device *dev, \ 6175d2364eSSrinivas Pandruvada struct device_attribute *dev_attr,\ 6275d2364eSSrinivas Pandruvada char *buf) \ 6375d2364eSSrinivas Pandruvada { \ 6475d2364eSSrinivas Pandruvada u64 value; \ 6575d2364eSSrinivas Pandruvada ssize_t len = -ENODATA; \ 6675d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); \ 6775d2364eSSrinivas Pandruvada int id; \ 6875d2364eSSrinivas Pandruvada struct powercap_zone_constraint *pconst;\ 6975d2364eSSrinivas Pandruvada \ 7075d2364eSSrinivas Pandruvada if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ 7175d2364eSSrinivas Pandruvada return -EINVAL; \ 7275d2364eSSrinivas Pandruvada if (id >= power_zone->const_id_cnt) \ 7375d2364eSSrinivas Pandruvada return -EINVAL; \ 7475d2364eSSrinivas Pandruvada pconst = &power_zone->constraints[id]; \ 7575d2364eSSrinivas Pandruvada if (pconst && pconst->ops && pconst->ops->get_##_attr) { \ 7675d2364eSSrinivas Pandruvada if (!pconst->ops->get_##_attr(power_zone, id, &value)) \ 7775d2364eSSrinivas Pandruvada len = sprintf(buf, "%lld\n", value); \ 7875d2364eSSrinivas Pandruvada } \ 7975d2364eSSrinivas Pandruvada \ 8075d2364eSSrinivas Pandruvada return len; \ 8175d2364eSSrinivas Pandruvada } 8275d2364eSSrinivas Pandruvada 8375d2364eSSrinivas Pandruvada /* Power zone constraint store function */ 8475d2364eSSrinivas Pandruvada #define define_power_zone_constraint_store(_attr) \ 8575d2364eSSrinivas Pandruvada static ssize_t store_constraint_##_attr(struct device *dev,\ 8675d2364eSSrinivas Pandruvada struct device_attribute *dev_attr, \ 8775d2364eSSrinivas Pandruvada const char *buf, size_t count) \ 8875d2364eSSrinivas Pandruvada { \ 8975d2364eSSrinivas Pandruvada int err; \ 9075d2364eSSrinivas Pandruvada u64 value; \ 9175d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); \ 9275d2364eSSrinivas Pandruvada int id; \ 9375d2364eSSrinivas Pandruvada struct powercap_zone_constraint *pconst;\ 9475d2364eSSrinivas Pandruvada \ 9575d2364eSSrinivas Pandruvada if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \ 9675d2364eSSrinivas Pandruvada return -EINVAL; \ 9775d2364eSSrinivas Pandruvada if (id >= power_zone->const_id_cnt) \ 9875d2364eSSrinivas Pandruvada return -EINVAL; \ 9975d2364eSSrinivas Pandruvada pconst = &power_zone->constraints[id]; \ 10075d2364eSSrinivas Pandruvada err = kstrtoull(buf, 10, &value); \ 10175d2364eSSrinivas Pandruvada if (err) \ 10275d2364eSSrinivas Pandruvada return -EINVAL; \ 10375d2364eSSrinivas Pandruvada if (pconst && pconst->ops && pconst->ops->set_##_attr) { \ 10475d2364eSSrinivas Pandruvada if (!pconst->ops->set_##_attr(power_zone, id, value)) \ 10575d2364eSSrinivas Pandruvada return count; \ 10675d2364eSSrinivas Pandruvada } \ 10775d2364eSSrinivas Pandruvada \ 10875d2364eSSrinivas Pandruvada return -ENODATA; \ 10975d2364eSSrinivas Pandruvada } 11075d2364eSSrinivas Pandruvada 11175d2364eSSrinivas Pandruvada /* Power zone information callbacks */ 11275d2364eSSrinivas Pandruvada define_power_zone_show(power_uw); 11375d2364eSSrinivas Pandruvada define_power_zone_show(max_power_range_uw); 11475d2364eSSrinivas Pandruvada define_power_zone_show(energy_uj); 11575d2364eSSrinivas Pandruvada define_power_zone_store(energy_uj); 11675d2364eSSrinivas Pandruvada define_power_zone_show(max_energy_range_uj); 11775d2364eSSrinivas Pandruvada 11875d2364eSSrinivas Pandruvada /* Power zone attributes */ 11975d2364eSSrinivas Pandruvada static DEVICE_ATTR_RO(max_power_range_uw); 12075d2364eSSrinivas Pandruvada static DEVICE_ATTR_RO(power_uw); 12175d2364eSSrinivas Pandruvada static DEVICE_ATTR_RO(max_energy_range_uj); 12275d2364eSSrinivas Pandruvada static DEVICE_ATTR_RW(energy_uj); 12375d2364eSSrinivas Pandruvada 12475d2364eSSrinivas Pandruvada /* Power zone constraint attributes callbacks */ 12575d2364eSSrinivas Pandruvada define_power_zone_constraint_show(power_limit_uw); 12675d2364eSSrinivas Pandruvada define_power_zone_constraint_store(power_limit_uw); 12775d2364eSSrinivas Pandruvada define_power_zone_constraint_show(time_window_us); 12875d2364eSSrinivas Pandruvada define_power_zone_constraint_store(time_window_us); 12975d2364eSSrinivas Pandruvada define_power_zone_constraint_show(max_power_uw); 13075d2364eSSrinivas Pandruvada define_power_zone_constraint_show(min_power_uw); 13175d2364eSSrinivas Pandruvada define_power_zone_constraint_show(max_time_window_us); 13275d2364eSSrinivas Pandruvada define_power_zone_constraint_show(min_time_window_us); 13375d2364eSSrinivas Pandruvada 13475d2364eSSrinivas Pandruvada /* For one time seeding of constraint device attributes */ 13575d2364eSSrinivas Pandruvada struct powercap_constraint_attr { 13675d2364eSSrinivas Pandruvada struct device_attribute power_limit_attr; 13775d2364eSSrinivas Pandruvada struct device_attribute time_window_attr; 13875d2364eSSrinivas Pandruvada struct device_attribute max_power_attr; 13975d2364eSSrinivas Pandruvada struct device_attribute min_power_attr; 14075d2364eSSrinivas Pandruvada struct device_attribute max_time_window_attr; 14175d2364eSSrinivas Pandruvada struct device_attribute min_time_window_attr; 14275d2364eSSrinivas Pandruvada struct device_attribute name_attr; 14375d2364eSSrinivas Pandruvada }; 14475d2364eSSrinivas Pandruvada 14575d2364eSSrinivas Pandruvada static struct powercap_constraint_attr 14675d2364eSSrinivas Pandruvada constraint_attrs[MAX_CONSTRAINTS_PER_ZONE]; 14775d2364eSSrinivas Pandruvada 14875d2364eSSrinivas Pandruvada /* A list of powercap control_types */ 14975d2364eSSrinivas Pandruvada static LIST_HEAD(powercap_cntrl_list); 15075d2364eSSrinivas Pandruvada /* Mutex to protect list of powercap control_types */ 15175d2364eSSrinivas Pandruvada static DEFINE_MUTEX(powercap_cntrl_list_lock); 15275d2364eSSrinivas Pandruvada 15375d2364eSSrinivas Pandruvada #define POWERCAP_CONSTRAINT_NAME_LEN 30 /* Some limit to avoid overflow */ 15475d2364eSSrinivas Pandruvada static ssize_t show_constraint_name(struct device *dev, 15575d2364eSSrinivas Pandruvada struct device_attribute *dev_attr, 15675d2364eSSrinivas Pandruvada char *buf) 15775d2364eSSrinivas Pandruvada { 15875d2364eSSrinivas Pandruvada const char *name; 15975d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); 16075d2364eSSrinivas Pandruvada int id; 16175d2364eSSrinivas Pandruvada ssize_t len = -ENODATA; 16275d2364eSSrinivas Pandruvada struct powercap_zone_constraint *pconst; 16375d2364eSSrinivas Pandruvada 16475d2364eSSrinivas Pandruvada if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) 16575d2364eSSrinivas Pandruvada return -EINVAL; 16675d2364eSSrinivas Pandruvada if (id >= power_zone->const_id_cnt) 16775d2364eSSrinivas Pandruvada return -EINVAL; 16875d2364eSSrinivas Pandruvada pconst = &power_zone->constraints[id]; 16975d2364eSSrinivas Pandruvada 17075d2364eSSrinivas Pandruvada if (pconst && pconst->ops && pconst->ops->get_name) { 17175d2364eSSrinivas Pandruvada name = pconst->ops->get_name(power_zone, id); 17275d2364eSSrinivas Pandruvada if (name) { 173*b4ba76fbSLukasz Luba sprintf(buf, "%.*s\n", POWERCAP_CONSTRAINT_NAME_LEN - 1, 174*b4ba76fbSLukasz Luba name); 17575d2364eSSrinivas Pandruvada len = strlen(buf); 17675d2364eSSrinivas Pandruvada } 17775d2364eSSrinivas Pandruvada } 17875d2364eSSrinivas Pandruvada 17975d2364eSSrinivas Pandruvada return len; 18075d2364eSSrinivas Pandruvada } 18175d2364eSSrinivas Pandruvada 18275d2364eSSrinivas Pandruvada static int create_constraint_attribute(int id, const char *name, 18375d2364eSSrinivas Pandruvada int mode, 18475d2364eSSrinivas Pandruvada struct device_attribute *dev_attr, 18575d2364eSSrinivas Pandruvada ssize_t (*show)(struct device *, 18675d2364eSSrinivas Pandruvada struct device_attribute *, char *), 18775d2364eSSrinivas Pandruvada ssize_t (*store)(struct device *, 18875d2364eSSrinivas Pandruvada struct device_attribute *, 18975d2364eSSrinivas Pandruvada const char *, size_t) 19075d2364eSSrinivas Pandruvada ) 19175d2364eSSrinivas Pandruvada { 19275d2364eSSrinivas Pandruvada 19375d2364eSSrinivas Pandruvada dev_attr->attr.name = kasprintf(GFP_KERNEL, "constraint_%d_%s", 19475d2364eSSrinivas Pandruvada id, name); 19575d2364eSSrinivas Pandruvada if (!dev_attr->attr.name) 19675d2364eSSrinivas Pandruvada return -ENOMEM; 19775d2364eSSrinivas Pandruvada dev_attr->attr.mode = mode; 19875d2364eSSrinivas Pandruvada dev_attr->show = show; 19975d2364eSSrinivas Pandruvada dev_attr->store = store; 20075d2364eSSrinivas Pandruvada 20175d2364eSSrinivas Pandruvada return 0; 20275d2364eSSrinivas Pandruvada } 20375d2364eSSrinivas Pandruvada 20475d2364eSSrinivas Pandruvada static void free_constraint_attributes(void) 20575d2364eSSrinivas Pandruvada { 20675d2364eSSrinivas Pandruvada int i; 20775d2364eSSrinivas Pandruvada 20875d2364eSSrinivas Pandruvada for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) { 20975d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].power_limit_attr.attr.name); 21075d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].time_window_attr.attr.name); 21175d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].name_attr.attr.name); 21275d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].max_power_attr.attr.name); 21375d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].min_power_attr.attr.name); 21475d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].max_time_window_attr.attr.name); 21575d2364eSSrinivas Pandruvada kfree(constraint_attrs[i].min_time_window_attr.attr.name); 21675d2364eSSrinivas Pandruvada } 21775d2364eSSrinivas Pandruvada } 21875d2364eSSrinivas Pandruvada 21975d2364eSSrinivas Pandruvada static int seed_constraint_attributes(void) 22075d2364eSSrinivas Pandruvada { 22175d2364eSSrinivas Pandruvada int i; 22275d2364eSSrinivas Pandruvada int ret; 22375d2364eSSrinivas Pandruvada 22475d2364eSSrinivas Pandruvada for (i = 0; i < MAX_CONSTRAINTS_PER_ZONE; ++i) { 22575d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "power_limit_uw", 22675d2364eSSrinivas Pandruvada S_IWUSR | S_IRUGO, 22775d2364eSSrinivas Pandruvada &constraint_attrs[i].power_limit_attr, 22875d2364eSSrinivas Pandruvada show_constraint_power_limit_uw, 22975d2364eSSrinivas Pandruvada store_constraint_power_limit_uw); 23075d2364eSSrinivas Pandruvada if (ret) 23175d2364eSSrinivas Pandruvada goto err_alloc; 23275d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "time_window_us", 23375d2364eSSrinivas Pandruvada S_IWUSR | S_IRUGO, 23475d2364eSSrinivas Pandruvada &constraint_attrs[i].time_window_attr, 23575d2364eSSrinivas Pandruvada show_constraint_time_window_us, 23675d2364eSSrinivas Pandruvada store_constraint_time_window_us); 23775d2364eSSrinivas Pandruvada if (ret) 23875d2364eSSrinivas Pandruvada goto err_alloc; 23975d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "name", S_IRUGO, 24075d2364eSSrinivas Pandruvada &constraint_attrs[i].name_attr, 24175d2364eSSrinivas Pandruvada show_constraint_name, 24275d2364eSSrinivas Pandruvada NULL); 24375d2364eSSrinivas Pandruvada if (ret) 24475d2364eSSrinivas Pandruvada goto err_alloc; 24575d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "max_power_uw", S_IRUGO, 24675d2364eSSrinivas Pandruvada &constraint_attrs[i].max_power_attr, 24775d2364eSSrinivas Pandruvada show_constraint_max_power_uw, 24875d2364eSSrinivas Pandruvada NULL); 24975d2364eSSrinivas Pandruvada if (ret) 25075d2364eSSrinivas Pandruvada goto err_alloc; 25175d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "min_power_uw", S_IRUGO, 25275d2364eSSrinivas Pandruvada &constraint_attrs[i].min_power_attr, 25375d2364eSSrinivas Pandruvada show_constraint_min_power_uw, 25475d2364eSSrinivas Pandruvada NULL); 25575d2364eSSrinivas Pandruvada if (ret) 25675d2364eSSrinivas Pandruvada goto err_alloc; 25775d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "max_time_window_us", 25875d2364eSSrinivas Pandruvada S_IRUGO, 25975d2364eSSrinivas Pandruvada &constraint_attrs[i].max_time_window_attr, 26075d2364eSSrinivas Pandruvada show_constraint_max_time_window_us, 26175d2364eSSrinivas Pandruvada NULL); 26275d2364eSSrinivas Pandruvada if (ret) 26375d2364eSSrinivas Pandruvada goto err_alloc; 26475d2364eSSrinivas Pandruvada ret = create_constraint_attribute(i, "min_time_window_us", 26575d2364eSSrinivas Pandruvada S_IRUGO, 26675d2364eSSrinivas Pandruvada &constraint_attrs[i].min_time_window_attr, 26775d2364eSSrinivas Pandruvada show_constraint_min_time_window_us, 26875d2364eSSrinivas Pandruvada NULL); 26975d2364eSSrinivas Pandruvada if (ret) 27075d2364eSSrinivas Pandruvada goto err_alloc; 27175d2364eSSrinivas Pandruvada 27275d2364eSSrinivas Pandruvada } 27375d2364eSSrinivas Pandruvada 27475d2364eSSrinivas Pandruvada return 0; 27575d2364eSSrinivas Pandruvada 27675d2364eSSrinivas Pandruvada err_alloc: 27775d2364eSSrinivas Pandruvada free_constraint_attributes(); 27875d2364eSSrinivas Pandruvada 27975d2364eSSrinivas Pandruvada return ret; 28075d2364eSSrinivas Pandruvada } 28175d2364eSSrinivas Pandruvada 28275d2364eSSrinivas Pandruvada static int create_constraints(struct powercap_zone *power_zone, 28375d2364eSSrinivas Pandruvada int nr_constraints, 284600c395bSJulia Lawall const struct powercap_zone_constraint_ops *const_ops) 28575d2364eSSrinivas Pandruvada { 28675d2364eSSrinivas Pandruvada int i; 28775d2364eSSrinivas Pandruvada int ret = 0; 28875d2364eSSrinivas Pandruvada int count; 28975d2364eSSrinivas Pandruvada struct powercap_zone_constraint *pconst; 29075d2364eSSrinivas Pandruvada 29175d2364eSSrinivas Pandruvada if (!power_zone || !const_ops || !const_ops->get_power_limit_uw || 29275d2364eSSrinivas Pandruvada !const_ops->set_power_limit_uw || 29375d2364eSSrinivas Pandruvada !const_ops->get_time_window_us || 29475d2364eSSrinivas Pandruvada !const_ops->set_time_window_us) 29575d2364eSSrinivas Pandruvada return -EINVAL; 29675d2364eSSrinivas Pandruvada 29775d2364eSSrinivas Pandruvada count = power_zone->zone_attr_count; 29875d2364eSSrinivas Pandruvada for (i = 0; i < nr_constraints; ++i) { 29975d2364eSSrinivas Pandruvada pconst = &power_zone->constraints[i]; 30075d2364eSSrinivas Pandruvada pconst->ops = const_ops; 30175d2364eSSrinivas Pandruvada pconst->id = power_zone->const_id_cnt; 30275d2364eSSrinivas Pandruvada power_zone->const_id_cnt++; 30375d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 30475d2364eSSrinivas Pandruvada &constraint_attrs[i].power_limit_attr.attr; 30575d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 30675d2364eSSrinivas Pandruvada &constraint_attrs[i].time_window_attr.attr; 30775d2364eSSrinivas Pandruvada if (pconst->ops->get_name) 30875d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 30975d2364eSSrinivas Pandruvada &constraint_attrs[i].name_attr.attr; 31075d2364eSSrinivas Pandruvada if (pconst->ops->get_max_power_uw) 31175d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 31275d2364eSSrinivas Pandruvada &constraint_attrs[i].max_power_attr.attr; 31375d2364eSSrinivas Pandruvada if (pconst->ops->get_min_power_uw) 31475d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 31575d2364eSSrinivas Pandruvada &constraint_attrs[i].min_power_attr.attr; 31675d2364eSSrinivas Pandruvada if (pconst->ops->get_max_time_window_us) 31775d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 31875d2364eSSrinivas Pandruvada &constraint_attrs[i].max_time_window_attr.attr; 31975d2364eSSrinivas Pandruvada if (pconst->ops->get_min_time_window_us) 32075d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 32175d2364eSSrinivas Pandruvada &constraint_attrs[i].min_time_window_attr.attr; 32275d2364eSSrinivas Pandruvada } 32375d2364eSSrinivas Pandruvada power_zone->zone_attr_count = count; 32475d2364eSSrinivas Pandruvada 32575d2364eSSrinivas Pandruvada return ret; 32675d2364eSSrinivas Pandruvada } 32775d2364eSSrinivas Pandruvada 32875d2364eSSrinivas Pandruvada static bool control_type_valid(void *control_type) 32975d2364eSSrinivas Pandruvada { 33075d2364eSSrinivas Pandruvada struct powercap_control_type *pos = NULL; 33175d2364eSSrinivas Pandruvada bool found = false; 33275d2364eSSrinivas Pandruvada 33375d2364eSSrinivas Pandruvada mutex_lock(&powercap_cntrl_list_lock); 33475d2364eSSrinivas Pandruvada 33575d2364eSSrinivas Pandruvada list_for_each_entry(pos, &powercap_cntrl_list, node) { 33675d2364eSSrinivas Pandruvada if (pos == control_type) { 33775d2364eSSrinivas Pandruvada found = true; 33875d2364eSSrinivas Pandruvada break; 33975d2364eSSrinivas Pandruvada } 34075d2364eSSrinivas Pandruvada } 34175d2364eSSrinivas Pandruvada mutex_unlock(&powercap_cntrl_list_lock); 34275d2364eSSrinivas Pandruvada 34375d2364eSSrinivas Pandruvada return found; 34475d2364eSSrinivas Pandruvada } 34575d2364eSSrinivas Pandruvada 34675d2364eSSrinivas Pandruvada static ssize_t name_show(struct device *dev, 34775d2364eSSrinivas Pandruvada struct device_attribute *attr, 34875d2364eSSrinivas Pandruvada char *buf) 34975d2364eSSrinivas Pandruvada { 35075d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); 35175d2364eSSrinivas Pandruvada 35275d2364eSSrinivas Pandruvada return sprintf(buf, "%s\n", power_zone->name); 35375d2364eSSrinivas Pandruvada } 35475d2364eSSrinivas Pandruvada 35575d2364eSSrinivas Pandruvada static DEVICE_ATTR_RO(name); 35675d2364eSSrinivas Pandruvada 35775d2364eSSrinivas Pandruvada /* Create zone and attributes in sysfs */ 35875d2364eSSrinivas Pandruvada static void create_power_zone_common_attributes( 35975d2364eSSrinivas Pandruvada struct powercap_zone *power_zone) 36075d2364eSSrinivas Pandruvada { 36175d2364eSSrinivas Pandruvada int count = 0; 36275d2364eSSrinivas Pandruvada 36375d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = &dev_attr_name.attr; 36475d2364eSSrinivas Pandruvada if (power_zone->ops->get_max_energy_range_uj) 36575d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 36675d2364eSSrinivas Pandruvada &dev_attr_max_energy_range_uj.attr; 36795677a9aSSrinivas Pandruvada if (power_zone->ops->get_energy_uj) { 36895677a9aSSrinivas Pandruvada if (power_zone->ops->reset_energy_uj) 369949dd010SLen Brown dev_attr_energy_uj.attr.mode = S_IWUSR | S_IRUSR; 37095677a9aSSrinivas Pandruvada else 371949dd010SLen Brown dev_attr_energy_uj.attr.mode = S_IRUSR; 37275d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 37375d2364eSSrinivas Pandruvada &dev_attr_energy_uj.attr; 37495677a9aSSrinivas Pandruvada } 37575d2364eSSrinivas Pandruvada if (power_zone->ops->get_power_uw) 37675d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 37775d2364eSSrinivas Pandruvada &dev_attr_power_uw.attr; 37875d2364eSSrinivas Pandruvada if (power_zone->ops->get_max_power_range_uw) 37975d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count++] = 38075d2364eSSrinivas Pandruvada &dev_attr_max_power_range_uw.attr; 38175d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[count] = NULL; 38275d2364eSSrinivas Pandruvada power_zone->zone_attr_count = count; 38375d2364eSSrinivas Pandruvada } 38475d2364eSSrinivas Pandruvada 38575d2364eSSrinivas Pandruvada static void powercap_release(struct device *dev) 38675d2364eSSrinivas Pandruvada { 38775d2364eSSrinivas Pandruvada bool allocated; 38875d2364eSSrinivas Pandruvada 38975d2364eSSrinivas Pandruvada if (dev->parent) { 39075d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); 39175d2364eSSrinivas Pandruvada 39275d2364eSSrinivas Pandruvada /* Store flag as the release() may free memory */ 39375d2364eSSrinivas Pandruvada allocated = power_zone->allocated; 39475d2364eSSrinivas Pandruvada /* Remove id from parent idr struct */ 39575d2364eSSrinivas Pandruvada idr_remove(power_zone->parent_idr, power_zone->id); 39675d2364eSSrinivas Pandruvada /* Destroy idrs allocated for this zone */ 39775d2364eSSrinivas Pandruvada idr_destroy(&power_zone->idr); 39875d2364eSSrinivas Pandruvada kfree(power_zone->name); 39975d2364eSSrinivas Pandruvada kfree(power_zone->zone_dev_attrs); 40075d2364eSSrinivas Pandruvada kfree(power_zone->constraints); 40175d2364eSSrinivas Pandruvada if (power_zone->ops->release) 40275d2364eSSrinivas Pandruvada power_zone->ops->release(power_zone); 40375d2364eSSrinivas Pandruvada if (allocated) 40475d2364eSSrinivas Pandruvada kfree(power_zone); 40575d2364eSSrinivas Pandruvada } else { 40675d2364eSSrinivas Pandruvada struct powercap_control_type *control_type = 40775d2364eSSrinivas Pandruvada to_powercap_control_type(dev); 40875d2364eSSrinivas Pandruvada 40975d2364eSSrinivas Pandruvada /* Store flag as the release() may free memory */ 41075d2364eSSrinivas Pandruvada allocated = control_type->allocated; 41175d2364eSSrinivas Pandruvada idr_destroy(&control_type->idr); 41275d2364eSSrinivas Pandruvada mutex_destroy(&control_type->lock); 41375d2364eSSrinivas Pandruvada if (control_type->ops && control_type->ops->release) 41475d2364eSSrinivas Pandruvada control_type->ops->release(control_type); 41575d2364eSSrinivas Pandruvada if (allocated) 41675d2364eSSrinivas Pandruvada kfree(control_type); 41775d2364eSSrinivas Pandruvada } 41875d2364eSSrinivas Pandruvada } 41975d2364eSSrinivas Pandruvada 42075d2364eSSrinivas Pandruvada static ssize_t enabled_show(struct device *dev, 42175d2364eSSrinivas Pandruvada struct device_attribute *attr, 42275d2364eSSrinivas Pandruvada char *buf) 42375d2364eSSrinivas Pandruvada { 42475d2364eSSrinivas Pandruvada bool mode = true; 42575d2364eSSrinivas Pandruvada 42675d2364eSSrinivas Pandruvada /* Default is enabled */ 42775d2364eSSrinivas Pandruvada if (dev->parent) { 42875d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); 42975d2364eSSrinivas Pandruvada if (power_zone->ops->get_enable) 43075d2364eSSrinivas Pandruvada if (power_zone->ops->get_enable(power_zone, &mode)) 43175d2364eSSrinivas Pandruvada mode = false; 43275d2364eSSrinivas Pandruvada } else { 43375d2364eSSrinivas Pandruvada struct powercap_control_type *control_type = 43475d2364eSSrinivas Pandruvada to_powercap_control_type(dev); 43575d2364eSSrinivas Pandruvada if (control_type->ops && control_type->ops->get_enable) 43675d2364eSSrinivas Pandruvada if (control_type->ops->get_enable(control_type, &mode)) 43775d2364eSSrinivas Pandruvada mode = false; 43875d2364eSSrinivas Pandruvada } 43975d2364eSSrinivas Pandruvada 44075d2364eSSrinivas Pandruvada return sprintf(buf, "%d\n", mode); 44175d2364eSSrinivas Pandruvada } 44275d2364eSSrinivas Pandruvada 44375d2364eSSrinivas Pandruvada static ssize_t enabled_store(struct device *dev, 44475d2364eSSrinivas Pandruvada struct device_attribute *attr, 44575d2364eSSrinivas Pandruvada const char *buf, size_t len) 44675d2364eSSrinivas Pandruvada { 44775d2364eSSrinivas Pandruvada bool mode; 44875d2364eSSrinivas Pandruvada 44975d2364eSSrinivas Pandruvada if (strtobool(buf, &mode)) 45075d2364eSSrinivas Pandruvada return -EINVAL; 45175d2364eSSrinivas Pandruvada if (dev->parent) { 45275d2364eSSrinivas Pandruvada struct powercap_zone *power_zone = to_powercap_zone(dev); 45375d2364eSSrinivas Pandruvada if (power_zone->ops->set_enable) 45475d2364eSSrinivas Pandruvada if (!power_zone->ops->set_enable(power_zone, mode)) 45575d2364eSSrinivas Pandruvada return len; 45675d2364eSSrinivas Pandruvada } else { 45775d2364eSSrinivas Pandruvada struct powercap_control_type *control_type = 45875d2364eSSrinivas Pandruvada to_powercap_control_type(dev); 45975d2364eSSrinivas Pandruvada if (control_type->ops && control_type->ops->set_enable) 46075d2364eSSrinivas Pandruvada if (!control_type->ops->set_enable(control_type, mode)) 46175d2364eSSrinivas Pandruvada return len; 46275d2364eSSrinivas Pandruvada } 46375d2364eSSrinivas Pandruvada 46475d2364eSSrinivas Pandruvada return -ENOSYS; 46575d2364eSSrinivas Pandruvada } 46675d2364eSSrinivas Pandruvada 4679e3410b7SThierry Reding static DEVICE_ATTR_RW(enabled); 4689e3410b7SThierry Reding 4699e3410b7SThierry Reding static struct attribute *powercap_attrs[] = { 4709e3410b7SThierry Reding &dev_attr_enabled.attr, 4719e3410b7SThierry Reding NULL, 47275d2364eSSrinivas Pandruvada }; 4739e3410b7SThierry Reding ATTRIBUTE_GROUPS(powercap); 47475d2364eSSrinivas Pandruvada 47575d2364eSSrinivas Pandruvada static struct class powercap_class = { 47675d2364eSSrinivas Pandruvada .name = "powercap", 47775d2364eSSrinivas Pandruvada .dev_release = powercap_release, 4789e3410b7SThierry Reding .dev_groups = powercap_groups, 47975d2364eSSrinivas Pandruvada }; 48075d2364eSSrinivas Pandruvada 48175d2364eSSrinivas Pandruvada struct powercap_zone *powercap_register_zone( 48275d2364eSSrinivas Pandruvada struct powercap_zone *power_zone, 48375d2364eSSrinivas Pandruvada struct powercap_control_type *control_type, 48475d2364eSSrinivas Pandruvada const char *name, 48575d2364eSSrinivas Pandruvada struct powercap_zone *parent, 48675d2364eSSrinivas Pandruvada const struct powercap_zone_ops *ops, 48775d2364eSSrinivas Pandruvada int nr_constraints, 488600c395bSJulia Lawall const struct powercap_zone_constraint_ops *const_ops) 48975d2364eSSrinivas Pandruvada { 49075d2364eSSrinivas Pandruvada int result; 49175d2364eSSrinivas Pandruvada int nr_attrs; 49275d2364eSSrinivas Pandruvada 49375d2364eSSrinivas Pandruvada if (!name || !control_type || !ops || 49475d2364eSSrinivas Pandruvada nr_constraints > MAX_CONSTRAINTS_PER_ZONE || 49575d2364eSSrinivas Pandruvada (!ops->get_energy_uj && !ops->get_power_uw) || 49675d2364eSSrinivas Pandruvada !control_type_valid(control_type)) 49775d2364eSSrinivas Pandruvada return ERR_PTR(-EINVAL); 49875d2364eSSrinivas Pandruvada 49975d2364eSSrinivas Pandruvada if (power_zone) { 50075d2364eSSrinivas Pandruvada if (!ops->release) 50175d2364eSSrinivas Pandruvada return ERR_PTR(-EINVAL); 50275d2364eSSrinivas Pandruvada memset(power_zone, 0, sizeof(*power_zone)); 50375d2364eSSrinivas Pandruvada } else { 50475d2364eSSrinivas Pandruvada power_zone = kzalloc(sizeof(*power_zone), GFP_KERNEL); 50575d2364eSSrinivas Pandruvada if (!power_zone) 50675d2364eSSrinivas Pandruvada return ERR_PTR(-ENOMEM); 50775d2364eSSrinivas Pandruvada power_zone->allocated = true; 50875d2364eSSrinivas Pandruvada } 50975d2364eSSrinivas Pandruvada power_zone->ops = ops; 51075d2364eSSrinivas Pandruvada power_zone->control_type_inst = control_type; 51175d2364eSSrinivas Pandruvada if (!parent) { 51275d2364eSSrinivas Pandruvada power_zone->dev.parent = &control_type->dev; 51375d2364eSSrinivas Pandruvada power_zone->parent_idr = &control_type->idr; 51475d2364eSSrinivas Pandruvada } else { 51575d2364eSSrinivas Pandruvada power_zone->dev.parent = &parent->dev; 51675d2364eSSrinivas Pandruvada power_zone->parent_idr = &parent->idr; 51775d2364eSSrinivas Pandruvada } 51875d2364eSSrinivas Pandruvada power_zone->dev.class = &powercap_class; 51975d2364eSSrinivas Pandruvada 52075d2364eSSrinivas Pandruvada mutex_lock(&control_type->lock); 52175d2364eSSrinivas Pandruvada /* Using idr to get the unique id */ 52275d2364eSSrinivas Pandruvada result = idr_alloc(power_zone->parent_idr, NULL, 0, 0, GFP_KERNEL); 52375d2364eSSrinivas Pandruvada if (result < 0) 52475d2364eSSrinivas Pandruvada goto err_idr_alloc; 52575d2364eSSrinivas Pandruvada 52675d2364eSSrinivas Pandruvada power_zone->id = result; 52775d2364eSSrinivas Pandruvada idr_init(&power_zone->idr); 528216c4e9dSDan Carpenter result = -ENOMEM; 52975d2364eSSrinivas Pandruvada power_zone->name = kstrdup(name, GFP_KERNEL); 53075d2364eSSrinivas Pandruvada if (!power_zone->name) 53175d2364eSSrinivas Pandruvada goto err_name_alloc; 53275d2364eSSrinivas Pandruvada dev_set_name(&power_zone->dev, "%s:%x", 53375d2364eSSrinivas Pandruvada dev_name(power_zone->dev.parent), 53475d2364eSSrinivas Pandruvada power_zone->id); 5356396bb22SKees Cook power_zone->constraints = kcalloc(nr_constraints, 5366396bb22SKees Cook sizeof(*power_zone->constraints), 5376396bb22SKees Cook GFP_KERNEL); 53875d2364eSSrinivas Pandruvada if (!power_zone->constraints) 53975d2364eSSrinivas Pandruvada goto err_const_alloc; 54075d2364eSSrinivas Pandruvada 54175d2364eSSrinivas Pandruvada nr_attrs = nr_constraints * POWERCAP_CONSTRAINTS_ATTRS + 54275d2364eSSrinivas Pandruvada POWERCAP_ZONE_MAX_ATTRS + 1; 5436396bb22SKees Cook power_zone->zone_dev_attrs = kcalloc(nr_attrs, sizeof(void *), 5446396bb22SKees Cook GFP_KERNEL); 54575d2364eSSrinivas Pandruvada if (!power_zone->zone_dev_attrs) 54675d2364eSSrinivas Pandruvada goto err_attr_alloc; 54775d2364eSSrinivas Pandruvada create_power_zone_common_attributes(power_zone); 54875d2364eSSrinivas Pandruvada result = create_constraints(power_zone, nr_constraints, const_ops); 54975d2364eSSrinivas Pandruvada if (result) 55075d2364eSSrinivas Pandruvada goto err_dev_ret; 55175d2364eSSrinivas Pandruvada 55275d2364eSSrinivas Pandruvada power_zone->zone_dev_attrs[power_zone->zone_attr_count] = NULL; 55375d2364eSSrinivas Pandruvada power_zone->dev_zone_attr_group.attrs = power_zone->zone_dev_attrs; 55475d2364eSSrinivas Pandruvada power_zone->dev_attr_groups[0] = &power_zone->dev_zone_attr_group; 55575d2364eSSrinivas Pandruvada power_zone->dev_attr_groups[1] = NULL; 55675d2364eSSrinivas Pandruvada power_zone->dev.groups = power_zone->dev_attr_groups; 55775d2364eSSrinivas Pandruvada result = device_register(&power_zone->dev); 55875d2364eSSrinivas Pandruvada if (result) 55975d2364eSSrinivas Pandruvada goto err_dev_ret; 56075d2364eSSrinivas Pandruvada 56175d2364eSSrinivas Pandruvada control_type->nr_zones++; 56275d2364eSSrinivas Pandruvada mutex_unlock(&control_type->lock); 56375d2364eSSrinivas Pandruvada 56475d2364eSSrinivas Pandruvada return power_zone; 56575d2364eSSrinivas Pandruvada 56675d2364eSSrinivas Pandruvada err_dev_ret: 56775d2364eSSrinivas Pandruvada kfree(power_zone->zone_dev_attrs); 56875d2364eSSrinivas Pandruvada err_attr_alloc: 56975d2364eSSrinivas Pandruvada kfree(power_zone->constraints); 57075d2364eSSrinivas Pandruvada err_const_alloc: 57175d2364eSSrinivas Pandruvada kfree(power_zone->name); 57275d2364eSSrinivas Pandruvada err_name_alloc: 57375d2364eSSrinivas Pandruvada idr_remove(power_zone->parent_idr, power_zone->id); 57475d2364eSSrinivas Pandruvada err_idr_alloc: 57575d2364eSSrinivas Pandruvada if (power_zone->allocated) 57675d2364eSSrinivas Pandruvada kfree(power_zone); 57775d2364eSSrinivas Pandruvada mutex_unlock(&control_type->lock); 57875d2364eSSrinivas Pandruvada 57975d2364eSSrinivas Pandruvada return ERR_PTR(result); 58075d2364eSSrinivas Pandruvada } 58175d2364eSSrinivas Pandruvada EXPORT_SYMBOL_GPL(powercap_register_zone); 58275d2364eSSrinivas Pandruvada 58375d2364eSSrinivas Pandruvada int powercap_unregister_zone(struct powercap_control_type *control_type, 58475d2364eSSrinivas Pandruvada struct powercap_zone *power_zone) 58575d2364eSSrinivas Pandruvada { 58675d2364eSSrinivas Pandruvada if (!power_zone || !control_type) 58775d2364eSSrinivas Pandruvada return -EINVAL; 58875d2364eSSrinivas Pandruvada 58975d2364eSSrinivas Pandruvada mutex_lock(&control_type->lock); 59075d2364eSSrinivas Pandruvada control_type->nr_zones--; 59175d2364eSSrinivas Pandruvada mutex_unlock(&control_type->lock); 59275d2364eSSrinivas Pandruvada 59375d2364eSSrinivas Pandruvada device_unregister(&power_zone->dev); 59475d2364eSSrinivas Pandruvada 59575d2364eSSrinivas Pandruvada return 0; 59675d2364eSSrinivas Pandruvada } 59775d2364eSSrinivas Pandruvada EXPORT_SYMBOL_GPL(powercap_unregister_zone); 59875d2364eSSrinivas Pandruvada 59975d2364eSSrinivas Pandruvada struct powercap_control_type *powercap_register_control_type( 60075d2364eSSrinivas Pandruvada struct powercap_control_type *control_type, 60175d2364eSSrinivas Pandruvada const char *name, 60275d2364eSSrinivas Pandruvada const struct powercap_control_type_ops *ops) 60375d2364eSSrinivas Pandruvada { 60475d2364eSSrinivas Pandruvada int result; 60575d2364eSSrinivas Pandruvada 60675d2364eSSrinivas Pandruvada if (!name) 60775d2364eSSrinivas Pandruvada return ERR_PTR(-EINVAL); 60875d2364eSSrinivas Pandruvada if (control_type) { 60975d2364eSSrinivas Pandruvada if (!ops || !ops->release) 61075d2364eSSrinivas Pandruvada return ERR_PTR(-EINVAL); 61175d2364eSSrinivas Pandruvada memset(control_type, 0, sizeof(*control_type)); 61275d2364eSSrinivas Pandruvada } else { 61375d2364eSSrinivas Pandruvada control_type = kzalloc(sizeof(*control_type), GFP_KERNEL); 61475d2364eSSrinivas Pandruvada if (!control_type) 61575d2364eSSrinivas Pandruvada return ERR_PTR(-ENOMEM); 61675d2364eSSrinivas Pandruvada control_type->allocated = true; 61775d2364eSSrinivas Pandruvada } 61875d2364eSSrinivas Pandruvada mutex_init(&control_type->lock); 61975d2364eSSrinivas Pandruvada control_type->ops = ops; 62075d2364eSSrinivas Pandruvada INIT_LIST_HEAD(&control_type->node); 62175d2364eSSrinivas Pandruvada control_type->dev.class = &powercap_class; 62208ff4cbeSSrinivas Pandruvada dev_set_name(&control_type->dev, "%s", name); 62375d2364eSSrinivas Pandruvada result = device_register(&control_type->dev); 62475d2364eSSrinivas Pandruvada if (result) { 62575d2364eSSrinivas Pandruvada if (control_type->allocated) 62675d2364eSSrinivas Pandruvada kfree(control_type); 62775d2364eSSrinivas Pandruvada return ERR_PTR(result); 62875d2364eSSrinivas Pandruvada } 62975d2364eSSrinivas Pandruvada idr_init(&control_type->idr); 63075d2364eSSrinivas Pandruvada 63175d2364eSSrinivas Pandruvada mutex_lock(&powercap_cntrl_list_lock); 63275d2364eSSrinivas Pandruvada list_add_tail(&control_type->node, &powercap_cntrl_list); 63375d2364eSSrinivas Pandruvada mutex_unlock(&powercap_cntrl_list_lock); 63475d2364eSSrinivas Pandruvada 63575d2364eSSrinivas Pandruvada return control_type; 63675d2364eSSrinivas Pandruvada } 63775d2364eSSrinivas Pandruvada EXPORT_SYMBOL_GPL(powercap_register_control_type); 63875d2364eSSrinivas Pandruvada 63975d2364eSSrinivas Pandruvada int powercap_unregister_control_type(struct powercap_control_type *control_type) 64075d2364eSSrinivas Pandruvada { 64175d2364eSSrinivas Pandruvada struct powercap_control_type *pos = NULL; 64275d2364eSSrinivas Pandruvada 64375d2364eSSrinivas Pandruvada if (control_type->nr_zones) { 64475d2364eSSrinivas Pandruvada dev_err(&control_type->dev, "Zones of this type still not freed\n"); 64575d2364eSSrinivas Pandruvada return -EINVAL; 64675d2364eSSrinivas Pandruvada } 64775d2364eSSrinivas Pandruvada mutex_lock(&powercap_cntrl_list_lock); 64875d2364eSSrinivas Pandruvada list_for_each_entry(pos, &powercap_cntrl_list, node) { 64975d2364eSSrinivas Pandruvada if (pos == control_type) { 65075d2364eSSrinivas Pandruvada list_del(&control_type->node); 65175d2364eSSrinivas Pandruvada mutex_unlock(&powercap_cntrl_list_lock); 65275d2364eSSrinivas Pandruvada device_unregister(&control_type->dev); 65375d2364eSSrinivas Pandruvada return 0; 65475d2364eSSrinivas Pandruvada } 65575d2364eSSrinivas Pandruvada } 65675d2364eSSrinivas Pandruvada mutex_unlock(&powercap_cntrl_list_lock); 65775d2364eSSrinivas Pandruvada 65875d2364eSSrinivas Pandruvada return -ENODEV; 65975d2364eSSrinivas Pandruvada } 66075d2364eSSrinivas Pandruvada EXPORT_SYMBOL_GPL(powercap_unregister_control_type); 66175d2364eSSrinivas Pandruvada 66275d2364eSSrinivas Pandruvada static int __init powercap_init(void) 66375d2364eSSrinivas Pandruvada { 6647f634489SArvind Yadav int result; 66575d2364eSSrinivas Pandruvada 66675d2364eSSrinivas Pandruvada result = seed_constraint_attributes(); 66775d2364eSSrinivas Pandruvada if (result) 66875d2364eSSrinivas Pandruvada return result; 66975d2364eSSrinivas Pandruvada 6707f634489SArvind Yadav return class_register(&powercap_class); 67175d2364eSSrinivas Pandruvada } 67275d2364eSSrinivas Pandruvada 673f76cb066SZhang Rui fs_initcall(powercap_init); 67475d2364eSSrinivas Pandruvada 67575d2364eSSrinivas Pandruvada MODULE_DESCRIPTION("PowerCap sysfs Driver"); 67675d2364eSSrinivas Pandruvada MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@linux.intel.com>"); 67775d2364eSSrinivas Pandruvada MODULE_LICENSE("GPL v2"); 678