diff mbox series

[V3] powernv: sensor-groups: Add debugfs file to enable/disable sensor groups

Message ID 1554954886-24460-1-git-send-email-shilpa.bhat@linux.vnet.ibm.com (mailing list archive)
State New
Headers show
Series [V3] powernv: sensor-groups: Add debugfs file to enable/disable sensor groups | expand

Checks

Context Check Description
snowpatch_ozlabs/apply_patch success Successfully applied on branch next (8c2ffd9174779014c3fe1f96d9dc3641d9175f00)
snowpatch_ozlabs/build-ppc64le success Build succeeded and removed 1 sparse warnings
snowpatch_ozlabs/build-ppc64be success Build succeeded and removed 1 sparse warnings
snowpatch_ozlabs/build-ppc64e success Build succeeded
snowpatch_ozlabs/build-pmac32 success Build succeeded
snowpatch_ozlabs/checkpatch warning total: 0 errors, 0 warnings, 1 checks, 372 lines checked

Commit Message

Shilpasri G Bhat April 11, 2019, 3:54 a.m. UTC
This patch provides support to disable and enable platform specific
sensor groups like performance, utilization and frequency which are
not supported in hwmon.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com>
---
Changes from V2:
- Rebase on master

Changes from V1:
- As per Michael Ellerman's suggestion, adding the "enable" files to debugfs.
  The original code had been written in mind to accomodate the "enable" file
  in the same path as "clear" attribute. As this is not required anymore
  the code is cleaned up to bifurcate the functions adding "enable" and
  "clear" attribute.

 .../powerpc/platforms/powernv/opal-sensor-groups.c | 292 ++++++++++++++-------
 1 file changed, 194 insertions(+), 98 deletions(-)
diff mbox series

Patch

diff --git a/arch/powerpc/platforms/powernv/opal-sensor-groups.c b/arch/powerpc/platforms/powernv/opal-sensor-groups.c
index 1796092..1208538 100644
--- a/arch/powerpc/platforms/powernv/opal-sensor-groups.c
+++ b/arch/powerpc/platforms/powernv/opal-sensor-groups.c
@@ -15,22 +15,21 @@ 
 #include <linux/kobject.h>
 #include <linux/slab.h>
 
+#include <asm/debugfs.h>
 #include <asm/opal.h>
 
-DEFINE_MUTEX(sg_mutex);
+#define SENSOR_GROUPS_DIR_STR	"sensor_groups"
 
 static struct kobject *sg_kobj;
 
-struct sg_attr {
-	u32 handle;
-	struct kobj_attribute attr;
-};
-
 static struct sensor_group {
-	char name[20];
+	struct kobj_attribute sattr;
 	struct attribute_group sg;
-	struct sg_attr *sgattrs;
-} *sgs;
+	struct mutex mutex;
+	char name[20];
+	u32 handle;
+	u32 enable;
+} *sgroups;
 
 int sensor_group_enable(u32 handle, bool enable)
 {
@@ -60,10 +59,12 @@  int sensor_group_enable(u32 handle, bool enable)
 }
 EXPORT_SYMBOL_GPL(sensor_group_enable);
 
-static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
-			const char *buf, size_t count)
+static ssize_t sgroup_clear_store(struct kobject *kobj,
+				  struct kobj_attribute *attr,
+				  const char *buf, size_t count)
 {
-	struct sg_attr *sattr = container_of(attr, struct sg_attr, attr);
+	struct sensor_group *sgroup = container_of(attr, struct sensor_group,
+						   sattr);
 	struct opal_msg msg;
 	u32 data;
 	int ret, token;
@@ -81,11 +82,11 @@  static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
 		return token;
 	}
 
-	ret = mutex_lock_interruptible(&sg_mutex);
+	ret = mutex_lock_interruptible(&sgroup->mutex);
 	if (ret)
 		goto out_token;
 
-	ret = opal_sensor_group_clear(sattr->handle, token);
+	ret = opal_sensor_group_clear(sgroup->handle, token);
 	switch (ret) {
 	case OPAL_ASYNC_COMPLETION:
 		ret = opal_async_wait_response(token, &msg);
@@ -106,135 +107,230 @@  static ssize_t sg_store(struct kobject *kobj, struct kobj_attribute *attr,
 	}
 
 out:
-	mutex_unlock(&sg_mutex);
+	mutex_unlock(&sgroup->mutex);
 out_token:
 	opal_async_release_token(token);
 	return ret;
 }
 
-static struct sg_ops_info {
-	int opal_no;
-	const char *attr_name;
-	ssize_t (*store)(struct kobject *kobj, struct kobj_attribute *attr,
-			const char *buf, size_t count);
-} ops_info[] = {
-	{ OPAL_SENSOR_GROUP_CLEAR, "clear", sg_store },
-};
+static int find_nr_groups(struct device_node *sensor_group_node, int opal_no)
+{
+	struct device_node *node;
+	int count = 0;
+
+	for_each_child_of_node(sensor_group_node, node) {
+		u32 sgid, op;
+
+		if (of_device_is_compatible(node, "ibm,opal-sensor"))
+			continue;
+
+		if (of_property_read_u32(node, "ops", &op))
+			continue;
+
+		if (op != opal_no)
+			continue;
+
+		if (of_property_read_u32(node, "sensor-group-id", &sgid))
+			continue;
+		count++;
+	}
 
-static void add_attr(int handle, struct sg_attr *attr, int index)
+	return count;
+}
+
+#ifdef CONFIG_DEBUG_FS
+static int sgroup_enable_get(void *data, u64 *val)
 {
-	attr->handle = handle;
-	sysfs_attr_init(&attr->attr.attr);
-	attr->attr.attr.name = ops_info[index].attr_name;
-	attr->attr.attr.mode = 0220;
-	attr->attr.store = ops_info[index].store;
+	struct sensor_group *sgroup = (struct sensor_group *)data;
+	int rc;
+
+	rc = mutex_lock_interruptible(&sgroup->mutex);
+	if (rc)
+		return rc;
+
+	*val = sgroup->enable;
+	mutex_unlock(&sgroup->mutex);
+
+	return 0;
 }
 
-static int add_attr_group(const __be32 *ops, int len, struct sensor_group *sg,
-			   u32 handle)
+static int sgroup_enable_set(void *data, u64 val)
 {
-	int i, j;
-	int count = 0;
+	struct sensor_group *sgroup = (struct sensor_group *)data;
+	int rc;
+
+	if (val != 0 && val != 1)
+		return -EINVAL;
 
-	for (i = 0; i < len; i++)
-		for (j = 0; j < ARRAY_SIZE(ops_info); j++)
-			if (be32_to_cpu(ops[i]) == ops_info[j].opal_no) {
-				add_attr(handle, &sg->sgattrs[count], j);
-				sg->sg.attrs[count] =
-					&sg->sgattrs[count].attr.attr;
-				count++;
-			}
+	rc = mutex_lock_interruptible(&sgroup->mutex);
+	if (rc)
+		return rc;
 
-	return sysfs_create_group(sg_kobj, &sg->sg);
+	if (val != sgroup->enable) {
+		rc = sensor_group_enable(sgroup->handle, val);
+		if (!rc)
+			sgroup->enable = val;
+	}
+
+	mutex_unlock(&sgroup->mutex);
+	return rc;
 }
 
-static int get_nr_attrs(const __be32 *ops, int len)
+DEFINE_DEBUGFS_ATTRIBUTE(sensor_debugfs_ops, sgroup_enable_get,
+			 sgroup_enable_set, "%llx\n");
+static struct dentry *sensor_debugfs_parent;
+static struct sensor_group *dgroups;
+
+static void add_debugfs_attrs(struct device_node *sensor_group_node)
 {
-	int i, j;
-	int nr_attrs = 0;
+	struct device_node *node;
+	int i = 0, count;
+
+	count = find_nr_groups(sensor_group_node, OPAL_SENSOR_GROUP_ENABLE);
+	if (!count)
+		return;
+
+	dgroups = kcalloc(count, sizeof(*dgroups), GFP_KERNEL);
+	if (!dgroups)
+		return;
+
+	sensor_debugfs_parent = debugfs_create_dir(SENSOR_GROUPS_DIR_STR,
+						   powerpc_debugfs_root);
 
-	for (i = 0; i < len; i++)
-		for (j = 0; j < ARRAY_SIZE(ops_info); j++)
-			if (be32_to_cpu(ops[i]) == ops_info[j].opal_no)
-				nr_attrs++;
+	if (!sensor_debugfs_parent)
+		goto out_dgroups;
 
-	return nr_attrs;
+	for_each_child_of_node(sensor_group_node, node) {
+		struct dentry *group;
+		u32 op, sgid, chipid;
+
+		if (of_device_is_compatible(node, "ibm,opal-sensor"))
+			continue;
+
+		if (of_property_read_u32(node, "ops", &op))
+			continue;
+
+		if (op != OPAL_SENSOR_GROUP_ENABLE)
+			continue;
+
+		if (of_property_read_u32(node, "sensor-group-id", &sgid))
+			continue;
+
+		if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
+			sprintf(dgroups[i].name, "%s%d", node->name, chipid);
+		else
+			sprintf(dgroups[i].name, "%s", node->name);
+
+		dgroups[i].handle = sgid;
+		dgroups[i].enable = 1;
+		mutex_init(&dgroups[i].mutex);
+		group = debugfs_create_dir(dgroups[i].name,
+					   sensor_debugfs_parent);
+		if (!group) {
+			of_node_put(node);
+			goto out_debugfs;
+		}
+
+		if (!debugfs_create_file("enable", 0664, group, &dgroups[i],
+					 &sensor_debugfs_ops)) {
+			of_node_put(node);
+			goto out_debugfs;
+		}
+		i++;
+	}
+
+	return;
+
+out_debugfs:
+	debugfs_remove_recursive(sensor_debugfs_parent);
+out_dgroups:
+	kfree(dgroups);
 }
+#endif /* CONFIG_DEBUG_FS */
 
 void __init opal_sensor_groups_init(void)
 {
-	struct device_node *sg, *node;
-	int i = 0;
+	struct device_node *sensor_group_node, *node;
+	int i = 0, count;
 
-	sg = of_find_compatible_node(NULL, NULL, "ibm,opal-sensor-group");
-	if (!sg) {
+	sensor_group_node = of_find_compatible_node(NULL, NULL,
+						    "ibm,opal-sensor-group");
+	if (!sensor_group_node) {
 		pr_devel("Sensor groups node not found\n");
 		return;
 	}
 
-	sgs = kcalloc(of_get_child_count(sg), sizeof(*sgs), GFP_KERNEL);
-	if (!sgs)
-		return;
+	count = find_nr_groups(sensor_group_node, OPAL_SENSOR_GROUP_CLEAR);
+	if (!count)
+		goto out_node_put;
+
+	sgroups = kcalloc(count, sizeof(*sgroups), GFP_KERNEL);
+	if (!sgroups)
+		goto out_node_put;
 
-	sg_kobj = kobject_create_and_add("sensor_groups", opal_kobj);
+	sg_kobj = kobject_create_and_add(SENSOR_GROUPS_DIR_STR, opal_kobj);
 	if (!sg_kobj) {
 		pr_warn("Failed to create sensor group kobject\n");
-		goto out_sgs;
+		goto out_sgroups;
 	}
 
-	for_each_child_of_node(sg, node) {
-		const __be32 *ops;
-		u32 sgid, len, nr_attrs, chipid;
+	for_each_child_of_node(sensor_group_node, node) {
+		u32 sgid, chipid, op;
 
-		ops = of_get_property(node, "ops", &len);
-		if (!ops)
+		if (of_property_read_u32(node, "ops", &op))
 			continue;
 
-		nr_attrs = get_nr_attrs(ops, len);
-		if (!nr_attrs)
+		if (op != OPAL_SENSOR_GROUP_CLEAR)
 			continue;
 
-		sgs[i].sgattrs = kcalloc(nr_attrs, sizeof(*sgs[i].sgattrs),
-					 GFP_KERNEL);
-		if (!sgs[i].sgattrs)
-			goto out_sgs_sgattrs;
-
-		sgs[i].sg.attrs = kcalloc(nr_attrs + 1,
-					  sizeof(*sgs[i].sg.attrs),
-					  GFP_KERNEL);
-
-		if (!sgs[i].sg.attrs) {
-			kfree(sgs[i].sgattrs);
-			goto out_sgs_sgattrs;
-		}
-
-		if (of_property_read_u32(node, "sensor-group-id", &sgid)) {
-			pr_warn("sensor-group-id property not found\n");
-			goto out_sgs_sgattrs;
-		}
+		if (of_property_read_u32(node, "sensor-group-id", &sgid))
+			continue;
 
 		if (!of_property_read_u32(node, "ibm,chip-id", &chipid))
-			sprintf(sgs[i].name, "%pOFn%d", node, chipid);
+			sprintf(sgroups[i].name, "%pOFn%d", node, chipid);
 		else
-			sprintf(sgs[i].name, "%pOFn", node);
+			sprintf(sgroups[i].name, "%pOFn", node);
+
+		sgroups[i].sg.attrs = kzalloc(sizeof(struct attribute *) * 2,
+					      GFP_KERNEL);
+		if (!sgroups[i].sg.attrs) {
+			of_node_put(node);
+			goto out_sg_attrs;
+		}
 
-		sgs[i].sg.name = sgs[i].name;
-		if (add_attr_group(ops, len, &sgs[i], sgid)) {
+		sgroups[i].sg.name = sgroups[i].name;
+		sgroups[i].handle = sgid;
+		sysfs_attr_init(sgroups[i].sattr.attr);
+		sgroups[i].sattr.attr.name = "clear";
+		sgroups[i].sattr.attr.mode = 0220;
+		sgroups[i].sattr.store = sgroup_clear_store;
+		sgroups[i].sg.attrs[0] = &sgroups[i].sattr.attr;
+		sgroups[i].sg.attrs[1] = NULL;
+		mutex_init(&sgroups[i].mutex);
+
+		if (sysfs_create_group(sg_kobj, &sgroups[i].sg)) {
 			pr_warn("Failed to create sensor attribute group %s\n",
-				sgs[i].sg.name);
-			goto out_sgs_sgattrs;
+				sgroups[i].sg.name);
+			kfree(sgroups[i].sg.attrs);
+			of_node_put(node);
+			goto out_sg_attrs;
 		}
+
 		i++;
 	}
 
-	return;
+#ifdef CONFIG_DEBUG_FS
+	add_debugfs_attrs(sensor_group_node);
+#endif /* CONFIG_DEBUG_FS */
 
-out_sgs_sgattrs:
-	while (--i >= 0) {
-		kfree(sgs[i].sgattrs);
-		kfree(sgs[i].sg.attrs);
-	}
+	goto out_node_put;
+
+out_sg_attrs:
+	while (i-- > 0)
+		kfree(sgroups[i].sg.attrs);
 	kobject_put(sg_kobj);
-out_sgs:
-	kfree(sgs);
+out_sgroups:
+	kfree(sgroups);
+out_node_put:
+	of_node_put(sensor_group_node);
 }