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