lists.openwall.net   lists  /  announce  owl-users  owl-dev  john-users  john-dev  passwdqc-users  yescrypt  popa3d-users  /  oss-security  kernel-hardening  musl  sabotage  tlsify  passwords  /  crypt-dev  xvendor  /  Bugtraq  Full-Disclosure  linux-kernel  linux-netdev  linux-ext4  linux-hardening  linux-cve-announce  PHC 
Open Source and information security mailing list archives
 
Hash Suite: Windows password security audit tool. GUI, reports in PDF.
[<prev] [next>] [<thread-prev] [thread-next>] [day] [month] [year] [list]
Message-Id: <1375891965-6921-3-git-send-email-srinivas.pandruvada@linux.intel.com>
Date:	Wed,  7 Aug 2013 09:12:42 -0700
From:	Srinivas Pandruvada <srinivas.pandruvada@...ux.intel.com>
To:	linux-kernel@...r.kernel.org
Cc:	gregkh@...uxfoundation.org, rjw@...k.pl, arjan@...ux.intel.com,
	len.brown@...el.com, jacob.jun.pan@...ux.intel.com, corbet@....net,
	joe@...ches.com,
	Srinivas Pandruvada <srinivas.pandruvada@...ux.intel.com>
Subject: [RFC v02 2/5] PowerCap: Add class driver

Added power cap class driver, which provides an API for client drivers
to use and provide a consistant sysfs interface to user mode.
For details on API refer to PowerCappingFramework.txt under
Documentation/powercap.

Signed-off-by: Srinivas Pandruvada <srinivas.pandruvada@...ux.intel.com>
Signed-off-by: Jacob Pan <jacob.jun.pan@...ux.intel.com>
Signed-off-by: Arjan van de Ven <arjan@...ux.intel.com>
---
 drivers/powercap/Kconfig        |  16 +
 drivers/powercap/Makefile       |   5 +
 drivers/powercap/powercap_sys.c | 995 ++++++++++++++++++++++++++++++++++++++++
 include/linux/powercap.h        | 300 ++++++++++++
 4 files changed, 1316 insertions(+)
 create mode 100644 drivers/powercap/Kconfig
 create mode 100644 drivers/powercap/Makefile
 create mode 100644 drivers/powercap/powercap_sys.c
 create mode 100644 include/linux/powercap.h

diff --git a/drivers/powercap/Kconfig b/drivers/powercap/Kconfig
new file mode 100644
index 0000000..f70b7b9
--- /dev/null
+++ b/drivers/powercap/Kconfig
@@ -0,0 +1,16 @@
+#
+# Generic powercap sysfs drivers configuration
+#
+
+menuconfig POWERCAP_SUPPORT
+	tristate "Generic powercap sysfs driver"
+	help
+	  A Power Capping Sysfs driver offers a generic mechanism for
+	  power capping. Usually it's made up of one or more controllers,
+	  power zones and constraints.
+	  If you want this support, you should say Y or M here.
+
+if POWERCAP_SUPPORT
+# Add client driver config here.
+
+endif
diff --git a/drivers/powercap/Makefile b/drivers/powercap/Makefile
new file mode 100644
index 0000000..f2acfed
--- /dev/null
+++ b/drivers/powercap/Makefile
@@ -0,0 +1,5 @@
+#
+# Makefile for powercap drivers
+#
+
+obj-$(CONFIG_POWERCAP_SUPPORT)	+= powercap_sys.o
diff --git a/drivers/powercap/powercap_sys.c b/drivers/powercap/powercap_sys.c
new file mode 100644
index 0000000..c15c8d4
--- /dev/null
+++ b/drivers/powercap/powercap_sys.c
@@ -0,0 +1,995 @@
+/*
+ * powercap sysfs class driver
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.
+ *
+ */
+
+#include <linux/module.h>
+#include <linux/device.h>
+#include <linux/err.h>
+#include <linux/slab.h>
+#include <linux/powercap.h>
+
+#define POWERCAP_CONSTRAINT_NAME_LEN		20
+#define POWERCAP_ZONE_CONSTRAINT_DEV_NAME_LEN	30
+
+/**
+ * struct powercap_zone_node- Defines a node containing power zones
+ * @next:		Pointer to sibling
+ * @children_count:	Number of children for this node
+ * @child:		Pointer to first child
+ * @parent:		Pointer to the parent
+ * @pcd_dev:		pointer to power zone device in this node
+ *
+ * A power zone node to be part of a tree.
+ */
+struct powercap_zone_node {
+	struct powercap_zone_node *next;
+	int children_count;
+	struct powercap_zone_node *child;
+	struct powercap_zone_node *parent;
+	struct powercap_zone_device *pcd_dev;
+};
+
+/**
+ * struct powercap_zone_constraint_attrs - Define constraint attribute
+ * @name:		Constraint attribute name.
+ * @attr:		Device attribute
+ *
+ * Define each attribute, with a name, based on the constraint id.
+ */
+struct powercap_constraint_attr {
+	char name[POWERCAP_ZONE_CONSTRAINT_DEV_NAME_LEN + 1];
+	struct device_attribute attr;
+};
+
+/**
+ * struct powercap_zone_constraint- Defines instance of a constraint
+ * @id:			Instance Id of this constraint.
+ * @pcd_dev:		Pointer to the power zone for this constraint.
+ * @ops:		Pointer to the constraint callbacks.
+ * @priv_data:		Constaint private data
+ * @list:		Link to other constraints for this power zone.
+ *
+ * This defines a constraint instance.
+ */
+struct powercap_zone_constraint {
+	int id;
+	struct powercap_zone_device *pcd_dev;
+	struct powercap_zone_constraint_ops *ops;
+	struct powercap_constraint_attr power_limit_attr;
+	struct powercap_constraint_attr time_window_attr;
+	struct powercap_constraint_attr max_power_attr;
+	struct powercap_constraint_attr min_power_attr;
+	struct powercap_constraint_attr max_time_window_attr;
+	struct powercap_constraint_attr min_time_window_attr;
+	struct powercap_constraint_attr name_attr;
+	struct list_head list;
+};
+
+/* A list of powercap controllers */
+static LIST_HEAD(powercap_cntrl_list);
+/* Mutex to protect list of powercap controllers */
+static DEFINE_MUTEX(powercap_cntrl_list_lock);
+
+/*
+ * Power Zone attributes: Each power zone registered with this framework
+ * contains two types of attributes:
+ * One with fixed name: E.g. energy_uj
+ * One with variable name: E.g. constraint_0_power_limit_uw
+ * Using two attribute groups, which will be used during device_register.
+ * The fixed name attributes are using static DEVICE_ATTR.
+ * For variable name device_attribute fields are initialized by assigning
+ * name (constraint_X_power_limit_uw, here X can be 0 to max integer).
+ */
+
+/* Power zone ro attributes define */
+#define powercap_attr_ro(_name)		\
+	static DEVICE_ATTR(_name, 0444, show_##_name, NULL)
+
+/* Power zone rw attributes define */
+#define powercap_attr_rw(_name)		\
+	static DEVICE_ATTR(_name, 0644, show_##_name, store_##_name)
+
+/* constraint attributes define rw */
+#define powercap_const_attr_rw(_name)		\
+	static DEVICE_ATTR(_name, 0644, show_constraint_##_name, \
+				store_constraint_##_name)
+/* constraint attributes define ro */
+#define powercap_const_attr_ro(_name)		\
+	static DEVICE_ATTR(_name, 0644, show_constraint_##_name, NULL)
+
+/* Power zone show function */
+#define define_device_show(_attr)		\
+static ssize_t show_##_attr(struct device *dev, \
+					struct device_attribute *dev_attr,\
+					char *buf) \
+{ \
+	u64 value; \
+	ssize_t len = -EINVAL; \
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev); \
+	\
+	if (pcd_dev && pcd_dev->ops && pcd_dev->ops->get_##_attr) { \
+		mutex_lock(&pcd_dev->lock); \
+		if (!pcd_dev->ops->get_##_attr(pcd_dev, &value)) \
+			len = sprintf(buf, "%lld\n", value); \
+		mutex_unlock(&pcd_dev->lock); \
+	} \
+	\
+	return len; \
+}
+
+/* Power zone store function; only reset is possible */
+#define define_device_store(_attr)		\
+static ssize_t store_##_attr(struct device *dev,\
+				struct device_attribute *dev_attr, \
+				const char *buf, size_t count) \
+{ \
+	int err; \
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev); \
+	u64 value; \
+	\
+	err = kstrtoull(buf, 10, &value); \
+	if (err) \
+		return -EINVAL; \
+	if (value) \
+		return -EINVAL; \
+	if (pcd_dev && pcd_dev->ops && pcd_dev->ops->reset_##_attr) { \
+		mutex_lock(&pcd_dev->lock); \
+		if (!pcd_dev->ops->reset_##_attr(pcd_dev)) { \
+			mutex_unlock(&pcd_dev->lock); \
+			return count; \
+		} \
+		mutex_unlock(&pcd_dev->lock); \
+	} \
+	\
+	return -EINVAL; \
+}
+
+/* Find constraint pointer from an ID */
+static struct powercap_zone_constraint *find_constraint(
+			struct powercap_zone_device *pcd_dev, int id)
+{
+	struct powercap_zone_constraint *pconst = NULL;
+
+	list_for_each_entry(pconst, &pcd_dev->constraint_list, list) {
+		if (pconst->id == id) {
+			return pconst;
+			break;
+		}
+	}
+
+	return pconst;
+}
+
+/* Power zone constraint show function */
+#define define_device_constraint_show(_attr) \
+static ssize_t show_constraint_##_attr(struct device *dev, \
+				struct device_attribute *dev_attr,\
+				char *buf) \
+{ \
+	u64 value; \
+	ssize_t len = -ENODATA; \
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev); \
+	int id; \
+	struct powercap_zone_constraint *pconst;\
+	\
+	if (!pcd_dev) \
+		return -EINVAL; \
+	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
+		return -EINVAL; \
+	mutex_lock(&pcd_dev->lock); \
+	pconst = find_constraint(pcd_dev, id); \
+	if (pconst && pconst->ops && pconst->ops->get_##_attr) { \
+		if (!pconst->ops->get_##_attr(pcd_dev, id, &value)) \
+			len = sprintf(buf, "%lld\n", value); \
+	} \
+	mutex_unlock(&pcd_dev->lock); \
+	\
+	return len; \
+}
+
+/* Power zone constraint store function */
+#define define_device_constraint_store(_attr) \
+static ssize_t store_constraint_##_attr(struct device *dev,\
+				struct device_attribute *dev_attr, \
+				const char *buf, size_t count) \
+{ \
+	int err; \
+	u64 value; \
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev); \
+	int id; \
+	struct powercap_zone_constraint *pconst;\
+	\
+	if (!pcd_dev) \
+		return -EINVAL; \
+	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id)) \
+		return -EINVAL; \
+	err = kstrtoull(buf, 10, &value); \
+	if (err) \
+		return -EINVAL; \
+	mutex_lock(&pcd_dev->lock); \
+	pconst = find_constraint(pcd_dev, id); \
+	if (pconst && pconst->ops && pconst->ops->set_##_attr) { \
+		if (!pconst->ops->set_##_attr(pcd_dev, id, value)) { \
+			mutex_unlock(&pcd_dev->lock); \
+			return count; \
+		} \
+	} \
+	mutex_unlock(&pcd_dev->lock); \
+	\
+	return -ENODATA; \
+}
+
+/* Power zone information callbacks */
+define_device_show(power_uw);
+define_device_store(power_uw);
+define_device_show(max_power_range_uw);
+define_device_show(energy_uj);
+define_device_store(energy_uj);
+define_device_show(max_energy_range_uj);
+
+/* Power zone attributes */
+powercap_attr_ro(max_power_range_uw);
+powercap_attr_rw(power_uw);
+powercap_attr_ro(max_energy_range_uj);
+powercap_attr_rw(energy_uj);
+
+/* Power zone constraint attributes callbacks */
+define_device_constraint_show(power_limit_uw);
+define_device_constraint_store(power_limit_uw);
+define_device_constraint_show(time_window_us);
+define_device_constraint_store(time_window_us);
+define_device_constraint_show(max_power_uw);
+define_device_constraint_show(min_power_uw);
+define_device_constraint_show(max_time_window_us);
+define_device_constraint_show(min_time_window_us);
+
+static ssize_t show_constraint_name(struct device *dev,
+				struct device_attribute *dev_attr,
+				char *buf)
+{
+	const char *name;
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev);
+	int id;
+	ssize_t len = -ENODATA;
+	struct powercap_zone_constraint *pconst;
+
+	if (!pcd_dev)
+		return -EINVAL;
+	if (!sscanf(dev_attr->attr.name, "constraint_%d_", &id))
+		return -EINVAL;
+	mutex_lock(&pcd_dev->lock);
+	pconst = find_constraint(pcd_dev, id);
+	if (pconst && pconst->ops && pconst->ops->get_name) {
+		name = pconst->ops->get_name(pcd_dev, id);
+		if (name) {
+			snprintf(buf, POWERCAP_CONSTRAINT_NAME_LEN,
+								"%s\n", name);
+			buf[POWERCAP_CONSTRAINT_NAME_LEN] = '\0';
+			len = strlen(buf);
+		}
+	}
+	mutex_unlock(&pcd_dev->lock);
+
+	return len;
+}
+
+static void create_constraint_attribute(struct powercap_zone_constraint *pconst,
+				const char *name,
+				int mode,
+				struct powercap_constraint_attr *attr,
+				ssize_t (*show)(struct device *,
+					struct device_attribute *, char *),
+				ssize_t (*store)(struct device *,
+					struct device_attribute *,
+				const char *, size_t)
+				)
+{
+	snprintf(attr->name, POWERCAP_ZONE_CONSTRAINT_DEV_NAME_LEN,
+					"constraint_%d_%s", pconst->id, name);
+	attr->name[POWERCAP_ZONE_CONSTRAINT_DEV_NAME_LEN] = '\0';
+	attr->attr.attr.name = attr->name;
+	attr->attr.attr.mode = mode;
+	attr->attr.show = show;
+	attr->attr.store = store;
+}
+
+/* Create a constraint attribute, if it has required call backs */
+static int create_constraints(struct powercap_zone_constraint *pconst)
+{
+	int count;
+	struct powercap_zone_device *pcd_dev;
+
+	if (!pconst->ops)
+		return -EINVAL;
+	if (!pconst->ops->get_power_limit_uw ||
+		!pconst->ops->set_power_limit_uw ||
+		!pconst->ops->get_time_window_us ||
+		!pconst->ops->set_time_window_us) {
+		return -EINVAL;
+	}
+	pcd_dev = pconst->pcd_dev;
+	count = pcd_dev->attrs.const_attr_count;
+	if (count >=
+		(POWERCAP_CONSTRAINTS_MAX_ATTRS - POWERCAP_CONSTRAINTS_ATTRS))
+		return -EINVAL;
+
+	create_constraint_attribute(pconst, "power_limit_uw",
+					S_IWUSR | S_IRUGO,
+					&pconst->power_limit_attr,
+					show_constraint_power_limit_uw,
+					store_constraint_power_limit_uw);
+	pcd_dev->attrs.const_dev_attrs[count++] =
+				&pconst->power_limit_attr.attr.attr;
+
+	create_constraint_attribute(pconst, "time_window_us",
+					S_IWUSR | S_IRUGO,
+					&pconst->time_window_attr,
+					show_constraint_time_window_us,
+					store_constraint_time_window_us);
+	pcd_dev->attrs.const_dev_attrs[count++] =
+				&pconst->time_window_attr.attr.attr;
+
+	if (pconst->ops->get_name) {
+		create_constraint_attribute(pconst, "name", S_IRUGO,
+				&pconst->name_attr,
+				show_constraint_name,
+				NULL);
+		pcd_dev->attrs.const_dev_attrs[count++] =
+				&pconst->name_attr.attr.attr;
+	}
+	if (pconst->ops->get_max_power_uw) {
+		create_constraint_attribute(pconst, "max_power_uw", S_IRUGO,
+					&pconst->max_power_attr,
+					show_constraint_max_power_uw,
+					NULL);
+		pcd_dev->attrs.const_dev_attrs[count++] =
+					&pconst->max_power_attr.attr.attr;
+	}
+	if (pconst->ops->get_min_power_uw) {
+		create_constraint_attribute(pconst, "min_power_uw", S_IRUGO,
+					&pconst->min_power_attr,
+					show_constraint_min_power_uw,
+					NULL);
+		pcd_dev->attrs.const_dev_attrs[count++] =
+					&pconst->min_power_attr.attr.attr;
+	}
+	if (pconst->ops->get_max_time_window_us) {
+		create_constraint_attribute(pconst, "max_time_window_us",
+					S_IRUGO,
+					&pconst->max_time_window_attr,
+					show_constraint_max_time_window_us,
+					NULL);
+		pcd_dev->attrs.const_dev_attrs[count++] =
+				&pconst->max_time_window_attr.attr.attr;
+	}
+	if (pconst->ops->get_min_time_window_us) {
+		create_constraint_attribute(pconst, "min_time_window_us",
+					S_IRUGO,
+					&pconst->min_time_window_attr,
+					show_constraint_min_time_window_us,
+					NULL);
+		pcd_dev->attrs.const_dev_attrs[count++] =
+				&pconst->min_time_window_attr.attr.attr;
+	}
+
+	pcd_dev->attrs.const_attr_count = count;
+
+	return 0;
+}
+
+struct powercap_zone_constraint *powercap_zone_add_constraint(
+				struct powercap_zone_device *pcd_dev,
+				struct powercap_zone_constraint_ops *ops)
+{
+	struct powercap_zone_constraint *pconst;
+	int result;
+
+	if (!pcd_dev)
+		return ERR_PTR(-EINVAL);
+
+	pconst = kzalloc(sizeof(*pconst), GFP_KERNEL);
+	if (!pconst)
+		return ERR_PTR(-ENOMEM);
+	/*
+	 * No need to hold locks as this is called when device
+	 * is not created or power zone is not in existance
+	 */
+	pconst->pcd_dev = pcd_dev;
+	pconst->ops = ops;
+	pconst->id = pcd_dev->const_id_cnt;
+	result = create_constraints(pconst);
+	if (result) {
+		kfree(pconst);
+		return ERR_PTR(result);
+	}
+	pcd_dev->const_id_cnt++;
+	list_add_tail(&pconst->list, &pcd_dev->constraint_list);
+
+	return pconst;
+}
+
+static void delete_constraints(struct powercap_zone_device *pcd_dev)
+{
+	struct powercap_zone_constraint *p, *n;
+
+	/*
+	 * No need to hold locks as this is called either when device
+	 * is not created or from device_release callback
+	 */
+	list_for_each_entry_safe(p, n, &pcd_dev->constraint_list, list) {
+		list_del(&p->list);
+		kfree(p);
+	}
+}
+
+static int create_constraint_attributes(struct powercap_zone_device *pcd_dev,
+				int nr_constraints,
+				struct powercap_zone_constraint_ops *const_ops)
+{
+	int i;
+	int ret = 0;
+
+	if (pcd_dev->attrs.attr_grp_cnt >= POWERCAP_MAX_ATTR_GROUPS)
+		return -ENOMEM;
+
+	for (i = 0; i < nr_constraints; ++i) {
+		if (!powercap_zone_add_constraint(pcd_dev, const_ops)) {
+			ret = -ENOMEM;
+			break;
+		}
+	}
+	if (ret) {
+		delete_constraints(pcd_dev);
+		return ret;
+	}
+	pcd_dev->attrs.const_dev_attrs[pcd_dev->attrs.const_attr_count] = NULL;
+	pcd_dev->attrs.dev_const_attr_group.attrs =
+						pcd_dev->attrs.const_dev_attrs;
+	pcd_dev->attrs.dev_attr_groups[pcd_dev->attrs.attr_grp_cnt] =
+					&pcd_dev->attrs.dev_const_attr_group;
+
+	pcd_dev->attrs.attr_grp_cnt++;
+
+	return ret;
+}
+
+/* Allocate a node of a tree */
+static struct powercap_zone_node *create_node(
+					struct powercap_zone_device *pcd_dev)
+{
+	struct powercap_zone_node *node;
+
+	node = kzalloc(sizeof(*node), GFP_KERNEL);
+	if (!node)
+		return NULL;
+
+	node->pcd_dev = pcd_dev;
+
+	return node;
+}
+
+/* Insert a node into a tree */
+static void insert_node(struct powercap_controller *ctrl,
+				struct powercap_zone_node *elem,
+				struct powercap_zone_node *parent)
+{
+	struct powercap_zone_node *node;
+
+	mutex_lock(&ctrl->node_lock);
+	if (!ctrl->root_node) {
+		ctrl->root_node = elem;
+		mutex_unlock(&ctrl->node_lock);
+		return;
+	}
+	if (!parent)
+		parent = ctrl->root_node;
+	elem->parent = parent;
+	if (!parent->child)
+		parent->child = elem;
+	else {
+		/* Not a first child */
+		node = parent->child;
+		while (node->next)
+			node = node->next;
+		node->next = elem;
+	}
+	parent->children_count++;
+	mutex_unlock(&ctrl->node_lock);
+}
+
+/*
+ * Delete a node, once node is deleted, its children nodes will be deleted.
+ * This is only deleting node, not freeing any memory for the zone.
+ * For each zone, del_callback is called, which unregister the device
+ * for the power zone. The memory is freed in the device release callback.
+ */
+static void delete_node(struct powercap_controller *ctrl,
+			struct powercap_zone_node *node,
+			void (*del_callback)(struct powercap_zone_device *))
+{
+	struct powercap_zone_node *node_store;
+	struct powercap_zone_node *node_limit = node;
+	bool root_node_delete = false;
+
+
+	mutex_lock(&ctrl->node_lock);
+
+	if (node == ctrl->root_node)
+		root_node_delete = true;
+
+	while (node) {
+		node_store = node;
+		if (node->child) {
+			node = node->child;
+		} else {
+			/* reached leaf node */
+			struct powercap_zone_node *_tnode;
+			if (node_store->pcd_dev) {
+				dev_dbg(&node_store->pcd_dev->device,
+				"Delete child %s of parent %s\n",
+				node_store->pcd_dev->name,
+				node_store->parent ?
+				node_store->parent->pcd_dev->name : "ROOT");
+			}
+			/* Point node to next sibling */
+			node = node_store->next;
+			if (!node)
+				node = node_store->parent; /* back to root */
+			/*
+			 *Before the leaf is deleted, remove references from
+			 *parent and siblings
+			 */
+			_tnode = node_store->parent;
+			if (_tnode) {
+				_tnode->children_count--;
+				if (_tnode->child == node_store) {
+					/*very first child*/
+					_tnode->child = node_store->next;
+				} else {
+					/*Not a first child*/
+					struct powercap_zone_node *_node =
+								_tnode->child;
+					struct powercap_zone_node *_pnode =
+								_node;
+
+					while (_node != node_store) {
+						_pnode = _node;
+						_node = _node->next;
+					}
+					_pnode->next = node_store->next;
+				}
+			}
+			if (node_store->pcd_dev) {
+				/* Ready to delete */
+				(*del_callback)(node_store->pcd_dev);
+			}
+			if (node_store == node_limit) {
+				kfree(node_store);
+				break;
+			}
+			kfree(node_store); /* Leaf node is freed */
+			/* zone memory is freed in the device_release */
+		}
+	}
+	/*
+	 * If the request was for root node,
+	 * then whole tree is deleted
+	 */
+	if (root_node_delete)
+		ctrl->root_node = NULL;
+
+	mutex_unlock(&ctrl->node_lock);
+}
+
+/* Search a tree for a controller for a zone instance */
+static bool search_node(struct powercap_controller *ctrl,
+			struct powercap_zone_device *pcd_dev)
+{
+	bool valid = true;
+	bool found = false;
+	struct powercap_zone_node *node;
+
+	mutex_lock(&ctrl->node_lock);
+
+	node = ctrl->root_node;
+
+	while (node) {
+		if (valid) {
+			if (node->pcd_dev == pcd_dev) {
+				found = true;
+				break;
+			}
+		}
+		/* First check if is node has children, then siblings */
+		if (node->child && valid) {
+			node = node->child;
+			valid = true;
+		} else if (node->next) {
+			node = node->next;
+			valid = true;
+		} else {
+			/* Reached leaf, go back to parent and traverse */
+			node = node->parent;
+			valid = false;
+		}
+	}
+	mutex_unlock(&ctrl->node_lock);
+
+	return found;
+}
+
+/* Check the presence of a controller in the controller list */
+static bool check_controller_validity(void *controller)
+{
+	struct powercap_controller *pos = NULL;
+	bool found = false;
+
+	mutex_lock(&powercap_cntrl_list_lock);
+
+	list_for_each_entry(pos, &powercap_cntrl_list, ctrl_inst) {
+		if (pos == controller) {
+			found = true;
+			break;
+		}
+	}
+	mutex_unlock(&powercap_cntrl_list_lock);
+
+	return found;
+}
+
+static ssize_t show_name(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev);
+
+	return sprintf(buf, "%s\n", pcd_dev->name);
+}
+
+static DEVICE_ATTR(name, 0444, show_name, NULL);
+
+/* Create zone and attributes in sysfs */
+static int create_power_zone_attributes(struct powercap_zone_device *pcd_dev)
+{
+
+	int count = 0;
+
+	pcd_dev->attrs.attr_grp_cnt = 0;
+	/**
+	* Limit is POWERCAP_ZONE_MAX_ATTRS = 10, Only adding 5 attrs.
+	* So not checking range after each addition
+	*/
+	pcd_dev->attrs.zone_dev_attrs[count++] = &dev_attr_name.attr;
+	if (pcd_dev->ops->get_max_energy_range_uj)
+		pcd_dev->attrs.zone_dev_attrs[count++] =
+					&dev_attr_max_energy_range_uj.attr;
+	if (pcd_dev->ops->get_energy_uj)
+		pcd_dev->attrs.zone_dev_attrs[count++] =
+					&dev_attr_energy_uj.attr;
+	if (pcd_dev->ops->get_power_uw)
+		pcd_dev->attrs.zone_dev_attrs[count++] =
+					&dev_attr_power_uw.attr;
+	if (pcd_dev->ops->get_max_power_range_uw)
+		pcd_dev->attrs.zone_dev_attrs[count++] =
+					&dev_attr_max_power_range_uw.attr;
+	pcd_dev->attrs.zone_dev_attrs[count] = NULL;
+	pcd_dev->attrs.zone_attr_count = count;
+	pcd_dev->attrs.dev_zone_attr_group.attrs =
+					pcd_dev->attrs.zone_dev_attrs;
+	pcd_dev->attrs.dev_attr_groups[0] =
+					&pcd_dev->attrs.dev_zone_attr_group;
+	pcd_dev->attrs.attr_grp_cnt++;
+
+	return 0;
+}
+
+static void delete_zone(struct powercap_zone_device *pcd_dev)
+{
+	struct powercap_zone_constraint *p;
+
+	dev_dbg(&pcd_dev->device, "deleting %s\n", pcd_dev->name);
+	mutex_lock(&pcd_dev->lock);
+
+	list_for_each_entry(p, &pcd_dev->constraint_list, list) {
+		if (p->ops->cleanup)
+			p->ops->cleanup(pcd_dev, p->id);
+	}
+	if (pcd_dev->ops->cleanup)
+		pcd_dev->ops->cleanup(pcd_dev);
+
+	mutex_unlock(&pcd_dev->lock);
+
+	device_unregister(&pcd_dev->device);
+}
+
+static void powercap_release(struct device *dev)
+{
+	if (dev->parent) {
+		struct powercap_zone_device *pcd_dev = dev_get_drvdata(dev);
+
+		dev_dbg(dev, "powercap_release zone %s\n", pcd_dev->name);
+
+		delete_constraints(pcd_dev);
+		/* Remove id from parent idr struct */
+		idr_remove(pcd_dev->par_idr, pcd_dev->id);
+		/* Destroy idrs allocated for this zone */
+		idr_destroy(&pcd_dev->idr);
+		kfree(pcd_dev->zone_dev_name);
+		mutex_destroy(&pcd_dev->lock);
+		kfree(pcd_dev);
+	} else {
+		struct powercap_controller *instance = dev_get_drvdata(dev);
+
+		dev_dbg(dev, "powercap_release controller %s\n",
+							instance->name);
+		idr_destroy(&instance->idr);
+		mutex_destroy(&instance->node_lock);
+		kfree(instance);
+	}
+}
+
+static ssize_t type_show(struct device *dev,
+				struct device_attribute *attr,
+				char *buf)
+{
+	if (dev->parent)
+		strcpy(buf, "power-zone\n");
+	else
+		strcpy(buf, "controller\n");
+
+	return strlen(buf);
+}
+
+static struct device_attribute powercap_def_attrs[] = {
+		__ATTR_RO(type),
+		__ATTR_NULL
+};
+
+static struct class powercap_class = {
+	.name = "power_cap",
+	.dev_release = powercap_release,
+	.dev_attrs = powercap_def_attrs,
+};
+
+struct powercap_zone_device *powercap_zone_register(
+				struct powercap_controller *controller,
+				const char *name,
+				struct powercap_zone_device *parent,
+				const struct powercap_zone_ops *ops,
+				int nr_constraints,
+				struct powercap_zone_constraint_ops *const_ops)
+{
+	int result;
+	struct powercap_zone_device *pcd_dev;
+	struct device *dev_ptr;
+	struct idr *idr_ptr;
+	char *parent_name;
+	int name_sz;
+
+	if (!name || !controller)
+		return ERR_PTR(-EINVAL);
+	if (strlen(name) > POWERCAP_ZONE_NAME_LENGTH)
+		return ERR_PTR(-EINVAL);
+	if (!ops)
+		return ERR_PTR(-EINVAL);
+	if (!ops->get_energy_uj && !ops->get_power_uw)
+		return ERR_PTR(-EINVAL);
+	if (!check_controller_validity(controller))
+		return ERR_PTR(-EINVAL);
+	if (parent && !search_node(controller, parent))
+		return ERR_PTR(-EINVAL);
+	pcd_dev = kzalloc(sizeof(*pcd_dev), GFP_KERNEL);
+	if (!pcd_dev)
+		return ERR_PTR(-ENOMEM);
+
+	INIT_LIST_HEAD(&pcd_dev->constraint_list);
+	mutex_init(&pcd_dev->lock);
+	pcd_dev->ops = ops;
+	pcd_dev->controller_inst = controller;
+	strncpy(pcd_dev->name, name, POWERCAP_ZONE_NAME_LENGTH);
+	pcd_dev->name[POWERCAP_ZONE_NAME_LENGTH] = '\0';
+	if (!parent) {
+		dev_ptr = &controller->device;
+		idr_ptr = &controller->idr;
+		parent_name = controller->name;
+	} else {
+		dev_ptr = &parent->device;
+		idr_ptr = &parent->idr;
+		parent_name = parent->zone_dev_name;
+	}
+	pcd_dev->par_idr = idr_ptr;
+	pcd_dev->device.class = &powercap_class;
+
+	/* allocate enough which can accommodate parent + ":" + int value */
+	name_sz = strlen(parent_name) +	sizeof(int)*2 + 2;
+	pcd_dev->zone_dev_name =  kmalloc(name_sz + 1, GFP_KERNEL);
+	if (!pcd_dev->zone_dev_name) {
+		result = -ENOMEM;
+		goto err_name_alloc;
+	}
+	mutex_lock(&controller->node_lock);
+	/* Using idr to get the unique id */
+	result = idr_alloc(pcd_dev->par_idr, NULL, 0, 0, GFP_KERNEL);
+	if (result < 0) {
+		mutex_unlock(&controller->node_lock);
+		goto err_idr_alloc;
+	}
+	pcd_dev->id = result;
+	idr_init(&pcd_dev->idr);
+
+	snprintf(pcd_dev->zone_dev_name, name_sz - 1, "%s:%x",
+						parent_name, pcd_dev->id);
+	pcd_dev->zone_dev_name[name_sz] = '\0';
+	dev_set_name(&pcd_dev->device, pcd_dev->zone_dev_name);
+	pcd_dev->device.parent = dev_ptr;
+
+	create_power_zone_attributes(pcd_dev);
+	result = create_constraint_attributes(pcd_dev, nr_constraints,
+								const_ops);
+	if (result) {
+		idr_remove(pcd_dev->par_idr, pcd_dev->id);
+		mutex_unlock(&controller->node_lock);
+		goto err_dev_reg;
+	}
+	pcd_dev->attrs.dev_attr_groups[pcd_dev->attrs.attr_grp_cnt] = NULL;
+	pcd_dev->device.groups = pcd_dev->attrs.dev_attr_groups;
+
+	result = device_register(&pcd_dev->device);
+	if (result) {
+		delete_constraints(pcd_dev);
+		idr_remove(pcd_dev->par_idr, pcd_dev->id);
+		mutex_unlock(&controller->node_lock);
+		goto err_dev_reg;
+	}
+	mutex_unlock(&controller->node_lock);
+
+	dev_set_drvdata(&pcd_dev->device, pcd_dev);
+	pcd_dev->node = create_node(pcd_dev);
+	if (!pcd_dev->node) {
+		result = -ENOMEM;
+		goto err_dev_reg_done;
+	}
+	if (parent)
+		insert_node(controller, pcd_dev->node, parent->node);
+	else
+		insert_node(controller, pcd_dev->node, NULL);
+
+	return pcd_dev;
+
+err_dev_reg:
+	idr_destroy(&pcd_dev->idr);
+err_idr_alloc:
+	kfree(pcd_dev->zone_dev_name);
+err_name_alloc:
+	mutex_destroy(&pcd_dev->lock);
+	kfree(pcd_dev);
+	return ERR_PTR(result);
+
+err_dev_reg_done:
+	device_unregister(&pcd_dev->device);
+	return ERR_PTR(result);
+}
+EXPORT_SYMBOL_GPL(powercap_zone_register);
+
+int powercap_zone_unregister(struct powercap_controller *controller,
+				struct powercap_zone_device *pcd_dev)
+{
+	if (!pcd_dev || !controller)
+		return -EINVAL;
+
+	if (!search_node(controller, pcd_dev))
+		return -EINVAL;
+
+	delete_node(controller, pcd_dev->node, delete_zone);
+
+	return 0;
+}
+EXPORT_SYMBOL_GPL(powercap_zone_unregister);
+
+struct powercap_controller *powercap_allocate_controller(
+					const char *controller_name)
+{
+	struct powercap_controller *cntrl;
+	int result;
+
+	if (!controller_name)
+		return ERR_PTR(-EINVAL);
+
+	if (strlen(controller_name) > POWERCAP_CTRL_NAME_LENGTH)
+		return ERR_PTR(-EINVAL);
+
+	cntrl = kzalloc(sizeof(struct powercap_controller), GFP_KERNEL);
+	if (!cntrl)
+		return ERR_PTR(-ENOMEM);
+
+	mutex_init(&cntrl->node_lock);
+	INIT_LIST_HEAD(&cntrl->ctrl_inst);
+	strncpy(cntrl->name, controller_name, POWERCAP_CTRL_NAME_LENGTH);
+	cntrl->name[POWERCAP_CTRL_NAME_LENGTH] = '\0';
+	cntrl->device.class = &powercap_class;
+	dev_set_name(&cntrl->device, cntrl->name);
+	result = device_register(&cntrl->device);
+	if (result) {
+		kfree(cntrl);
+		return ERR_PTR(result);
+	}
+	dev_set_drvdata(&cntrl->device, cntrl);
+
+	cntrl->root_node = create_node(NULL);
+	if (!cntrl->root_node) {
+		result = -ENOMEM;
+		goto unregister;
+	}
+	idr_init(&cntrl->idr);
+	mutex_lock(&powercap_cntrl_list_lock);
+	list_add_tail(&cntrl->ctrl_inst, &powercap_cntrl_list);
+	mutex_unlock(&powercap_cntrl_list_lock);
+
+	return cntrl;
+
+unregister:
+	device_unregister(&cntrl->device);
+	return ERR_PTR(result);
+}
+EXPORT_SYMBOL_GPL(powercap_allocate_controller);
+
+void powercap_deallocate_controller(struct powercap_controller *instance)
+{
+	struct powercap_controller *pos = NULL;
+
+	mutex_lock(&powercap_cntrl_list_lock);
+
+	list_for_each_entry(pos, &powercap_cntrl_list, ctrl_inst) {
+		if (pos == instance)
+			break;
+	}
+	if (pos != instance) {
+		/* instance not found */
+		mutex_unlock(&powercap_cntrl_list_lock);
+		return;
+	}
+	list_del(&instance->ctrl_inst);
+	delete_node(instance, instance->root_node, delete_zone);
+
+	mutex_unlock(&powercap_cntrl_list_lock);
+
+	device_unregister(&instance->device);
+}
+EXPORT_SYMBOL_GPL(powercap_deallocate_controller);
+
+static int __init powercap_init(void)
+{
+	int result = 0;
+
+	result = class_register(&powercap_class);
+	if (result)
+		return result;
+
+	return result;
+}
+
+static void __exit powercap_exit(void)
+{
+	class_unregister(&powercap_class);
+}
+
+fs_initcall(powercap_init);
+module_exit(powercap_exit);
+
+MODULE_DESCRIPTION("PowerCap sysfs Driver");
+MODULE_AUTHOR("Srinivas Pandruvada <srinivas.pandruvada@...ux.intel.com>");
+MODULE_LICENSE("GPL v2");
diff --git a/include/linux/powercap.h b/include/linux/powercap.h
new file mode 100644
index 0000000..9967bd0
--- /dev/null
+++ b/include/linux/powercap.h
@@ -0,0 +1,300 @@
+/*
+ * powercap.h : Exports all power class sysfs interface
+ * Copyright (c) 2013, Intel Corporation.
+ *
+ * This program is free software; you can redistribute it and/or modify it
+ * under the terms and conditions of the GNU General Public License,
+ * version 2, as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.
+ *
+ */
+
+#ifndef __POWERCAP_H__
+#define __POWERCAP_H__
+
+#include <linux/device.h>
+#include <linux/idr.h>
+
+/*
+ * A power cap class device can contain multiple powercap controllers.
+ * Each controller can have multiple power zones, which can be independently
+ * controlled. Each power zone can have one or more constraints.
+ */
+
+#define POWERCAP_CTRL_NAME_LENGTH			30
+#define POWERCAP_ZONE_NAME_LENGTH			30
+
+struct powercap_zone_device;
+struct powercap_zone_constraint;
+
+/**
+ * struct powercap_zone_constraint_ops - Define constraint callbacks
+ * @set_power_limit_uw:		Set power limit in micro-watts.
+ * @get_power_limit_uw:		Get power limit in micro-watts.
+ * @set_time_window_us:		Set time window in micro-seconds.
+ * @get_time_window_us:		Get time window in micro-seconds.
+ * @get_max_power_uw:		Get max power allowed in micro-watts.
+ * @get_min_power_uw:		Get min power allowed in micro-watts.
+ * @get_max_time_window_us:	Get max time window allowed in micro-seconds.
+ * @get_min_time_window_us:	Get min time window allowed in micro-seconds.
+ * @get_name:			Get the name of constraint
+ * @cleanup:			Do any clean up before the constraint is freed
+ * This structure is used to define the constraint callbacks for the client
+ * drivers. The following callbacks are mandatory and can't be NULL:
+ *  set_power_limit_uw
+ *  get_power_limit_uw
+ *  set_time_window_us
+ *  get_time_window_us
+ *  get_name
+ */
+struct powercap_zone_constraint_ops {
+	int (*set_power_limit_uw)
+			(struct powercap_zone_device *, int, u64);
+	int (*get_power_limit_uw)
+			(struct powercap_zone_device *, int, u64 *);
+
+	int (*set_time_window_us)
+			(struct powercap_zone_device *, int, u64);
+	int (*get_time_window_us)
+			(struct powercap_zone_device *, int, u64 *);
+
+	int (*get_max_power_uw)
+			(struct powercap_zone_device *, int, u64 *);
+	int (*get_min_power_uw)
+			(struct powercap_zone_device *, int, u64 *);
+
+	int (*get_max_time_window_us)
+			(struct powercap_zone_device *, int, u64 *);
+	int (*get_min_time_window_us)
+			(struct powercap_zone_device *, int, u64 *);
+	const char *(*get_name) (struct powercap_zone_device *, int);
+	void (*cleanup) (struct powercap_zone_device *, int);
+};
+
+/**
+ * struct powercap_controller- Defines a powercap controller
+ * @name:		name of controller
+ * @device:		device for this controller
+ * @idr	:		idr to have unique id for its child
+ * @root_node:		Root holding power zones for this controller
+ * @node_lock:		mutex for node
+ * @ctrl_inst:		link to the controller list
+ *
+ * Defines powercap controller instance
+ */
+struct powercap_controller {
+	char name[POWERCAP_CTRL_NAME_LENGTH + 1];
+	struct device device;
+	struct idr idr;
+	void *root_node;
+	struct mutex node_lock;
+	struct list_head ctrl_inst;
+};
+
+/**
+ * struct powercap_zone_ops - Define power zone callbacks
+ * @get_max_energy_range_uj:	Get maximum range of energy counter in
+ *				micro-joules.
+ * @get_energy_uj:		Get current energy counter in micro-joules.
+ * @reset_energy_uj:		Reset micro-joules energy counter.
+ * @get_max_power_range_uw:	Get maximum range of power counter in
+ *				micro-watts.
+ * @get_power_uw:		Get current power counter in micro-watts.
+ * @reset_power_uw:		Reset micro-watts power counter.
+ * @cleanup:			Do any clean up before the zone is freed
+ *
+ * This structure defines zone callbacks to be implemented by client drivers.
+ * Client drives can define both energy and power related callbacks. But at
+ * the least one type (either power or energy) is mandatory.
+ */
+struct powercap_zone_ops {
+	int (*get_max_energy_range_uj)
+			(struct powercap_zone_device *, u64 *);
+	int (*get_energy_uj)
+			(struct powercap_zone_device *, u64 *);
+	int (*reset_energy_uj)
+			(struct powercap_zone_device *);
+
+	int (*get_max_power_range_uw)
+			(struct powercap_zone_device *, u64 *);
+	int (*get_power_uw)
+			(struct powercap_zone_device *, u64 *);
+	int (*reset_power_uw) (struct powercap_zone_device *);
+
+	void (*cleanup) (struct powercap_zone_device *);
+};
+
+#define	POWERCAP_ZONE_MAX_ATTRS		10 /* Currently only max 5 */
+#define	POWERCAP_CONSTRAINTS_ATTRS	8  /*  5 attrs/constraints */
+#define	POWERCAP_CONSTRAINTS_MAX_ATTRS	10 * POWERCAP_CONSTRAINTS_ATTRS
+					/* For 10 constraints per zone */
+#define POWERCAP_MAX_ATTR_GROUPS	2 /* One for zone and constraint */
+/**
+ * struct powercap_zone_attr- Defines a per zone attribute group
+ * @zone_dev_attrs:	Device attribute list for power zone.
+ * @zone_attr_count:	Number of power zone attributes.
+ * @const_dev_attrs:	Constraint attributes.
+ * @const_attr_count:	Number of constraint related attributes
+ * @dev_zone_attr_group: Attribute group for power zone attributes
+ * @dev_const_attr_group: Attribute group for constraints
+ * @attr_grp_cnt:	Number of attribute groups
+ * @dev_attr_groups:	Used to assign to dev->group
+ *
+ * Used to add an attribute group unique to a zone based on registry.
+ */
+struct powercap_zone_attr {
+	struct attribute *zone_dev_attrs[POWERCAP_ZONE_MAX_ATTRS];
+	int zone_attr_count;
+	struct attribute *const_dev_attrs[POWERCAP_CONSTRAINTS_MAX_ATTRS];
+	int const_attr_count;
+	struct attribute_group dev_zone_attr_group;
+	struct attribute_group dev_const_attr_group;
+	int attr_grp_cnt;
+	const struct attribute_group
+			*dev_attr_groups[POWERCAP_MAX_ATTR_GROUPS + 1];
+};
+
+/**
+ * struct powercap_zone_device- Defines instance of a power cap zone
+ * @id:			Unique id
+ * @zone_dev_name:	Zone device sysfs node name
+ * @name:		Power zone name.
+ * @controller_inst:	Controller instance for this zone
+ * @ops:		Pointer to the zone operation structure.
+ * @device:		Instance of a device.
+ * @attrs:		Attributes associated with this device
+ * @node:		Node pointer to insert to a tree data structure.
+ * @const_id_cnt:	Constraint id count
+ * @lock:		Mutex to protect zone related operations.
+ * @idr:		Instance to an idr entry for children zones.
+ * @par_idr:		To remove reference from the parent idr
+ * @drv_data:		Driver private data
+ * @constraint_list:	Link to the next power zone for this controller.
+ *
+ * This defines a power zone instance. The fields of this structure are
+ * private, and should not be used by client drivers.
+ */
+struct powercap_zone_device {
+	int id;
+	char *zone_dev_name;
+	char name[POWERCAP_ZONE_NAME_LENGTH + 1];
+	void *controller_inst;
+	const struct powercap_zone_ops *ops;
+	struct device device;
+	struct powercap_zone_attr attrs;
+	void *node;
+	int const_id_cnt;
+	struct mutex lock;
+	struct idr idr;
+	struct idr *par_idr;
+	void *drv_data;
+	struct list_head constraint_list;
+};
+
+/* For clients to get their device pointer, may be used for dev_dbgs */
+#define POWERCAP_GET_DEV(p_zone)	(&pzone->device)
+
+/**
+* powercap_set_zone_data() - Set private data for a zone
+* @pcd_dev:	A pointer to the valid zone instance.
+* @pdata:	A pointer to the user private data.
+*
+* Allows client drivers to associate some private data to zone instance.
+*/
+static inline void powercap_set_zone_data(struct powercap_zone_device *pcd_dev,
+						void *pdata)
+{
+	if (pcd_dev)
+		pcd_dev->drv_data = pdata;
+}
+
+/**
+* powercap_get_zone_data() - Get private data for a zone
+* @pcd_dev:	A pointer to the valid zone instance.
+*
+* Allows client drivers to get private data associate with a zone,
+* using call to powercap_set_zone_data.
+*/
+static inline void *powercap_get_zone_data(struct powercap_zone_device *pcd_dev)
+{
+	if (pcd_dev)
+		return pcd_dev->drv_data;
+	return NULL;
+}
+
+/* Controller allocate/deallocate API */
+
+/**
+* powercap_allocate_controller() - Allocates a controller
+* @controller_name:	The Name of this controller, which will be shown
+*			in the sysfs Interface.
+*
+* Used to create a controller with the power capping class. Here controller
+* can represent a type of technology, which can control a range of power zones.
+* For example a controller can be RAPL (Running Average Power Limit)
+* IntelĀ® 64 and IA-32 Processor Architectures. The name can be any string
+* which must be unique, otherwise this function returns NULL.
+* On successful allocation, this API returns a pointer to the
+* controller instance.
+*/
+struct powercap_controller *powercap_allocate_controller(
+						const char *controller_name);
+
+/**
+* powercap_deallocate_controller() - Deallocates a controller
+* @instance:	A pointer to the valid controller instance.
+*
+* Used to deallocate a controller with the power capping class. This
+* takes only one argument, which is the pointer to the instance returned
+* by a call to powercap_allocate_controller.
+* When a controller is deallocated, all zones and associated constraints
+* are freed.
+*/
+void powercap_deallocate_controller(struct powercap_controller *instance);
+
+/* Zone register/unregister API */
+
+/**
+* powercap_zone_register() - Register a power zone
+* @controller:	A controller instance under which this zone operates.
+* @name:	A name for this zone.
+* @parent:	A pointer to the parent power zone instance if any or NULL
+* @ops:		Pointer to zone operation callback structure.
+* @no_constraints: Number of constraints for this zone
+* @const_ops:	Pointer to constraint callback structure
+*
+* Used to register a power zone for a controller. Zones are organized in
+* a tree like structure in sysfs under a controller.
+* A power zone must a register a pointer to a structure representing zone
+* callbacks.
+* A power zone can have a some other power zone as a parent or it can be
+* NULL to appear as a direct descendant of a controller.
+* Each power zone can have number of constraints. Constraints appears
+* under zones as attributes with unique id.
+*/
+struct powercap_zone_device *powercap_zone_register(
+			struct powercap_controller *controller,
+			const char *name,
+			struct powercap_zone_device *parent,
+			const struct powercap_zone_ops *ops,
+			int no_constraints,
+			struct powercap_zone_constraint_ops *const_ops);
+/**
+* powercap_zone_unregister() - Unregister a zone device
+* @controller:	A pointer to the valid instance of a controller.
+* @pcd_dev:	A pointer to the valid zone instance for a controller
+*
+* Used to unregister a zone device for a controller. Once a zone is
+* unregistered then all its children and associated constraints are freed.
+*/
+int powercap_zone_unregister(struct powercap_controller *controller,
+				struct powercap_zone_device *pcd_dev);
+
+#endif
-- 
1.8.3.1

--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to majordomo@...r.kernel.org
More majordomo info at  http://vger.kernel.org/majordomo-info.html
Please read the FAQ at  http://www.tux.org/lkml/

Powered by blists - more mailing lists

Powered by Openwall GNU/*/Linux Powered by OpenVZ