[PATCH V8 0/3] powernv : Add support for OPAL-OCC command/response interface

STALE3298d

Revision v8 of 5 in this series.

9 messages, 3 authors, 2017-07-28 · open the first message on its own page

[PATCH V8 0/3] powernv : Add support for OPAL-OCC command/response interface

From: Shilpasri G Bhat <hidden>
Date: 2017-07-26 05:05:26

In P9, OCC (On-Chip-Controller) supports shared memory based
commad-response interface. Within the shared memory there is an OPAL
command buffer and OCC response buffer that can be used to send
inband commands to OCC. The following commands are supported:

1) Set system powercap
2) Set CPU-GPU power shifting ratio
3) Clear min/max for OCC sensor groups

The skiboot patch for this interface is posted here:
https://lists.ozlabs.org/pipermail/skiboot/2017-July/008352.html

Shilpasri G Bhat (3):
  powernv: powercap: Add support for powercap framework
  powernv: Add support to set power-shifting-ratio
  powernv: Add support to clear sensor groups data

 arch/powerpc/include/asm/opal-api.h            |   8 +-
 arch/powerpc/include/asm/opal.h                |   9 +
 arch/powerpc/include/uapi/asm/opal-occ.h       |  23 +++
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-occ.c      | 109 ++++++++++++
 arch/powerpc/platforms/powernv/opal-powercap.c | 237 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-psr.c      | 169 ++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   5 +
 arch/powerpc/platforms/powernv/opal.c          |  10 ++
 9 files changed, 570 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/include/uapi/asm/opal-occ.h
 create mode 100644 arch/powerpc/platforms/powernv/opal-occ.c
 create mode 100644 arch/powerpc/platforms/powernv/opal-powercap.c
 create mode 100644 arch/powerpc/platforms/powernv/opal-psr.c

-- 
1.8.3.1

[PATCH V8 1/3] powernv: powercap: Add support for powercap framework

From: Shilpasri G Bhat <hidden>
Date: 2017-07-26 05:05:29

Adds a generic powercap framework to change the system powercap
inband through OPAL-OCC command/response interface.

Signed-off-by: Shilpasri G Bhat <redacted>
---
Changes from V7:
- Replaced sscanf with kstrtoint

 arch/powerpc/include/asm/opal-api.h            |   5 +-
 arch/powerpc/include/asm/opal.h                |   4 +
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-powercap.c | 237 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +
 arch/powerpc/platforms/powernv/opal.c          |   4 +
 6 files changed, 252 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-powercap.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 3130a73..c3e0c4a 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -42,6 +42,7 @@
 #define OPAL_I2C_STOP_ERR	-24
 #define OPAL_XIVE_PROVISIONING	-31
 #define OPAL_XIVE_FREE_ACTIVE	-32
+#define OPAL_TIMEOUT		-33
 
 /* API Tokens (in r0) */
 #define OPAL_INVALID_CALL		       -1
@@ -190,7 +191,9 @@
 #define OPAL_NPU_INIT_CONTEXT			146
 #define OPAL_NPU_DESTROY_CONTEXT		147
 #define OPAL_NPU_MAP_LPAR			148
-#define OPAL_LAST				148
+#define OPAL_GET_POWERCAP			152
+#define OPAL_SET_POWERCAP			153
+#define OPAL_LAST				153
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 588fb1c..ec2087c 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -267,6 +267,8 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int64_t opal_xive_free_irq(uint32_t girq);
 int64_t opal_xive_sync(uint32_t type, uint32_t id);
 int64_t opal_xive_dump(uint32_t type, uint32_t id);
+int opal_get_powercap(u32 handle, int token, u32 *pcap);
+int opal_set_powercap(u32 handle, int token, u32 pcap);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -345,6 +347,8 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 
 void opal_wake_poller(void);
 
+void opal_powercap_init(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index b5d98cb..e79f806 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o
+obj-y			+= opal-kmsg.o opal-powercap.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c
new file mode 100644
index 0000000..7c57f4b
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-powercap.c
@@ -0,0 +1,237 @@
+/*
+ * PowerNV OPAL Powercap interface
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt)     "opal-powercap: " fmt
+
+#include <linux/of.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include <asm/opal.h>
+
+DEFINE_MUTEX(powercap_mutex);
+
+static struct kobject *powercap_kobj;
+
+struct powercap_attr {
+	u32 handle;
+	struct kobj_attribute attr;
+};
+
+static struct attribute_group *pattr_groups;
+static struct powercap_attr *pcap_attrs;
+
+static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr,
+			     char *buf)
+{
+	struct powercap_attr *pcap_attr = container_of(attr,
+						struct powercap_attr, attr);
+	struct opal_msg msg;
+	u32 pcap;
+	int ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&powercap_mutex);
+	ret = opal_get_powercap(pcap_attr->handle, token, &pcap);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
+		break;
+	case OPAL_SUCCESS:
+		ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&powercap_mutex);
+	opal_async_release_token(token);
+	return ret;
+}
+
+static ssize_t powercap_store(struct kobject *kobj,
+			      struct kobj_attribute *attr, const char *buf,
+			      size_t count)
+{
+	struct powercap_attr *pcap_attr = container_of(attr,
+						struct powercap_attr, attr);
+	struct opal_msg msg;
+	u32 pcap;
+	int ret, token;
+
+	ret = kstrtoint(buf, 0, &pcap);
+	if (ret)
+		return ret;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&powercap_mutex);
+	ret = opal_set_powercap(pcap_attr->handle, token, pcap);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = count;
+		break;
+	case OPAL_SUCCESS:
+		ret = count;
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&powercap_mutex);
+	opal_async_release_token(token);
+
+	return ret;
+}
+
+static void powercap_add_attr(int handle, const char *name,
+			      struct powercap_attr *attr)
+{
+	attr->handle = handle;
+	sysfs_attr_init(&attr->attr.attr);
+	attr->attr.attr.name = name;
+	attr->attr.attr.mode = 0444;
+	attr->attr.show = powercap_show;
+}
+
+void __init opal_powercap_init(void)
+{
+	struct device_node *powercap, *node;
+	int pattr_group_count = 0, total_attr_count = 0;
+	int i, count;
+
+	powercap = of_find_node_by_path("/ibm,opal/power-mgt/powercap");
+	if (!powercap) {
+		pr_devel("/ibm,opal/power-mgt/powercap node not found\n");
+		return;
+	}
+
+	for_each_child_of_node(powercap, node)
+		pattr_group_count++;
+
+	pattr_groups = kcalloc(pattr_group_count,
+			       sizeof(struct attribute_group), GFP_KERNEL);
+	if (!pattr_groups)
+		return;
+
+	i = 0;
+	for_each_child_of_node(powercap, node) {
+		int attr_count = 0;
+
+		if (of_find_property(node, "powercap-min", NULL))
+			attr_count++;
+		if (of_find_property(node, "powercap-max", NULL))
+			attr_count++;
+		if (of_find_property(node, "powercap-cur", NULL))
+			attr_count++;
+
+		total_attr_count += attr_count;
+		pattr_groups[i].attrs = kcalloc(attr_count + 1,
+						sizeof(struct attribute *),
+						GFP_KERNEL);
+		if (!pattr_groups[i].attrs) {
+			while (--i >= 0)
+				kfree(pattr_groups[i].attrs);
+			goto out_pattr_groups;
+		}
+		i++;
+	}
+
+	pcap_attrs = kcalloc(total_attr_count, sizeof(struct powercap_attr),
+			     GFP_KERNEL);
+	if (!pcap_attrs)
+		goto out_pattr_groups_attrs;
+
+	count = 0;
+	i = 0;
+	for_each_child_of_node(powercap, node) {
+		u32 handle;
+		int j = 0;
+
+		pattr_groups[i].name = node->name;
+
+		if (!of_property_read_u32(node, "powercap-min", &handle)) {
+			powercap_add_attr(handle, "powercap-min",
+					  &pcap_attrs[count]);
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+
+		if (!of_property_read_u32(node, "powercap-max", &handle)) {
+			powercap_add_attr(handle, "powercap-max",
+					  &pcap_attrs[count]);
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+
+		if (!of_property_read_u32(node, "powercap-cur", &handle)) {
+			powercap_add_attr(handle, "powercap-cur",
+					  &pcap_attrs[count]);
+			pcap_attrs[count].attr.attr.mode |= 0220;
+			pcap_attrs[count].attr.store = powercap_store;
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+		i++;
+	}
+
+	powercap_kobj = kobject_create_and_add("powercap", opal_kobj);
+	if (!powercap_kobj) {
+		pr_warn("Failed to create powercap kobject\n");
+		goto out_pcap_attrs;
+	}
+
+	for (i = 0; i < pattr_group_count; i++) {
+		if (sysfs_create_group(powercap_kobj, &pattr_groups[i])) {
+			pr_warn("Failed to create powercap attribute group %s\n",
+				pattr_groups[i].name);
+			goto out;
+		}
+	}
+
+	return;
+out:
+	kobject_put(powercap_kobj);
+out_pcap_attrs:
+	kfree(pcap_attrs);
+out_pattr_groups_attrs:
+	while (--pattr_group_count >= 0)
+		kfree(pattr_groups[i].attrs);
+out_pattr_groups:
+	kfree(pattr_groups);
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 4ca6c26..eff5fe7 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -310,3 +310,5 @@ OPAL_CALL(opal_xive_dump,			OPAL_XIVE_DUMP);
 OPAL_CALL(opal_npu_init_context,		OPAL_NPU_INIT_CONTEXT);
 OPAL_CALL(opal_npu_destroy_context,		OPAL_NPU_DESTROY_CONTEXT);
 OPAL_CALL(opal_npu_map_lpar,			OPAL_NPU_MAP_LPAR);
+OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
+OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index cad6b57..889da97 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -836,6 +836,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL kmsg dumper for flushing console on panic */
 	opal_kmsg_init();
 
+	/* Initialise OPAL powercap interface */
+	opal_powercap_init();
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
@@ -952,6 +955,7 @@ int opal_error_code(int rc)
 	case OPAL_UNSUPPORTED:		return -EIO;
 	case OPAL_HARDWARE:		return -EIO;
 	case OPAL_INTERNAL_ERROR:	return -EIO;
+	case OPAL_TIMEOUT:		return -ETIMEDOUT;
 	default:
 		pr_err("%s: unexpected OPAL error %d\n", __func__, rc);
 		return -EIO;
-- 
1.8.3.1

[PATCH V8 3/3] powernv: Add support to clear sensor groups data

From: Shilpasri G Bhat <hidden>
Date: 2017-07-26 05:05:35

Adds support for clearing different sensor groups. OCC inband sensor
groups like CSM, Profiler, Job Scheduler can be cleared using this
driver. The min/max of all sensors belonging to these sensor groups
will be cleared.

Signed-off-by: Shilpasri G Bhat <redacted>
---
Changes from V7:
- s/send_occ_command/opal_sensor_groups_clear_history

 arch/powerpc/include/asm/opal-api.h            |   3 +-
 arch/powerpc/include/asm/opal.h                |   2 +
 arch/powerpc/include/uapi/asm/opal-occ.h       |  23 ++++++
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-occ.c      | 109 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   1 +
 arch/powerpc/platforms/powernv/opal.c          |   3 +
 7 files changed, 141 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/include/uapi/asm/opal-occ.h
 create mode 100644 arch/powerpc/platforms/powernv/opal-occ.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0d37315..342738a 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -195,7 +195,8 @@
 #define OPAL_SET_POWERCAP			153
 #define OPAL_GET_PSR				154
 #define OPAL_SET_PSR				155
-#define OPAL_LAST				155
+#define OPAL_SENSOR_GROUPS_CLEAR		156
+#define OPAL_LAST				156
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 58b30a4..92db6af 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -271,6 +271,7 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int opal_set_powercap(u32 handle, int token, u32 pcap);
 int opal_get_power_shifting_ratio(u32 handle, int token, u32 *psr);
 int opal_set_power_shifting_ratio(u32 handle, int token, u32 psr);
+int opal_sensor_groups_clear(u32 group_hndl, int token);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -351,6 +352,7 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 
 void opal_powercap_init(void);
 void opal_psr_init(void);
+int opal_sensor_groups_clear_history(u32 handle);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/powerpc/include/uapi/asm/opal-occ.h b/arch/powerpc/include/uapi/asm/opal-occ.h
new file mode 100644
index 0000000..97c45e2
--- /dev/null
+++ b/arch/powerpc/include/uapi/asm/opal-occ.h
@@ -0,0 +1,23 @@
+/*
+ * OPAL OCC command interface
+ * Supported on POWERNV platform
+ *
+ * (C) Copyright IBM 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _UAPI_ASM_POWERPC_OPAL_OCC_H_
+#define _UAPI_ASM_POWERPC_OPAL_OCC_H_
+
+#define OPAL_OCC_IOCTL_CLEAR_SENSOR_GROUPS	_IOR('o', 1, u32)
+
+#endif /* _UAPI_ASM_POWERPC_OPAL_OCC_H */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 9ed7d33..f193b33 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o
+obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o opal-occ.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-occ.c b/arch/powerpc/platforms/powernv/opal-occ.c
new file mode 100644
index 0000000..d1d4b28
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-occ.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright IBM Corporation 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#define pr_fmt(fmt) "opal-occ: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <asm/opal.h>
+#include <asm/opal-occ.h>
+
+DEFINE_MUTEX(opal_occ_mutex);
+
+int opal_sensor_groups_clear_history(u32 handle)
+{
+	struct opal_msg async_msg;
+	int token, rc;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get the token %d\n", token);
+		return token;
+	}
+
+	mutex_lock(&opal_occ_mutex);
+	rc = opal_sensor_groups_clear(handle, token);
+	if (rc == OPAL_ASYNC_COMPLETION) {
+		rc = opal_async_wait_response(token, &async_msg);
+		if (rc) {
+			pr_devel("Failed to wait for async response %d\n", rc);
+			goto out;
+		}
+		rc = opal_get_async_rc(async_msg);
+	}
+out:
+	mutex_unlock(&opal_occ_mutex);
+	opal_async_release_token(token);
+	return opal_error_code(rc);
+}
+EXPORT_SYMBOL_GPL(opal_sensor_groups_clear_history);
+
+static long opal_occ_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long param)
+{
+	int rc = -EINVAL;
+
+	switch (cmd) {
+	case OPAL_OCC_IOCTL_CLEAR_SENSOR_GROUPS:
+		rc = opal_sensor_groups_clear_history(param);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static const struct file_operations opal_occ_fops = {
+	.unlocked_ioctl = opal_occ_ioctl,
+	.owner		= THIS_MODULE,
+};
+
+static struct miscdevice occ_dev = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "occ",
+	.fops	= &opal_occ_fops,
+};
+
+static int opal_occ_probe(struct platform_device *pdev)
+{
+	return misc_register(&occ_dev);
+}
+
+static int opal_occ_remove(struct platform_device *pdev)
+{
+	misc_deregister(&occ_dev);
+	return 0;
+}
+
+static const struct of_device_id opal_occ_match[] = {
+	{ .compatible = "ibm,opal-occ-sensor-group" },
+	{ },
+};
+
+static struct platform_driver opal_occ_driver = {
+	.driver = {
+		.name           = "opal-occ",
+		.of_match_table = opal_occ_match,
+	},
+	.probe	= opal_occ_probe,
+	.remove	= opal_occ_remove,
+};
+
+module_platform_driver(opal_occ_driver);
+
+MODULE_DESCRIPTION("PowerNV OPAL-OCC driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 9867726..c1130e8 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -314,3 +314,4 @@ OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
 OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
 OPAL_CALL(opal_get_power_shifting_ratio,	OPAL_GET_PSR);
 OPAL_CALL(opal_set_power_shifting_ratio,	OPAL_SET_PSR);
+OPAL_CALL(opal_sensor_groups_clear,		OPAL_SENSOR_GROUPS_CLEAR);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 280a736..097c33c 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -842,6 +842,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL Power-Shifting-Ratio interface */
 	opal_psr_init();
 
+	/* Initialize platform device: OCC interface */
+	opal_pdev_init("ibm,opal-occ-sensor-group");
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
-- 
1.8.3.1

[PATCH V8 2/3] powernv: Add support to set power-shifting-ratio

From: Shilpasri G Bhat <hidden>
Date: 2017-07-26 05:06:46

This patch adds support to set power-shifting-ratio for CPU-GPU which
is used by OCC power capping algorithm.

Signed-off-by: Shilpasri G Bhat <redacted>
---
Changes from V7:
- Replaced sscanf with kstrtoint

 arch/powerpc/include/asm/opal-api.h            |   4 +-
 arch/powerpc/include/asm/opal.h                |   3 +
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-psr.c      | 169 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +
 arch/powerpc/platforms/powernv/opal.c          |   3 +
 6 files changed, 181 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-psr.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index c3e0c4a..0d37315 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -193,7 +193,9 @@
 #define OPAL_NPU_MAP_LPAR			148
 #define OPAL_GET_POWERCAP			152
 #define OPAL_SET_POWERCAP			153
-#define OPAL_LAST				153
+#define OPAL_GET_PSR				154
+#define OPAL_SET_PSR				155
+#define OPAL_LAST				155
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ec2087c..58b30a4 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -269,6 +269,8 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int64_t opal_xive_dump(uint32_t type, uint32_t id);
 int opal_get_powercap(u32 handle, int token, u32 *pcap);
 int opal_set_powercap(u32 handle, int token, u32 pcap);
+int opal_get_power_shifting_ratio(u32 handle, int token, u32 *psr);
+int opal_set_power_shifting_ratio(u32 handle, int token, u32 psr);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -348,6 +350,7 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 void opal_wake_poller(void);
 
 void opal_powercap_init(void);
+void opal_psr_init(void);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index e79f806..9ed7d33 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o opal-powercap.o
+obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-psr.c b/arch/powerpc/platforms/powernv/opal-psr.c
new file mode 100644
index 0000000..07e3f78
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-psr.c
@@ -0,0 +1,169 @@
+/*
+ * PowerNV OPAL Power-Shifting-Ratio interface
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt)     "opal-psr: " fmt
+
+#include <linux/of.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include <asm/opal.h>
+
+DEFINE_MUTEX(psr_mutex);
+
+static struct kobject *psr_kobj;
+
+struct psr_attr {
+	u32 handle;
+	struct kobj_attribute attr;
+};
+
+static struct psr_attr *psr_attrs;
+static struct kobject *psr_kobj;
+
+static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			char *buf)
+{
+	struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
+	struct opal_msg msg;
+	int psr, ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&psr_mutex);
+	ret = opal_get_power_shifting_ratio(psr_attr->handle, token, &psr);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
+		break;
+	case OPAL_SUCCESS:
+		ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&psr_mutex);
+	opal_async_release_token(token);
+	return ret;
+}
+
+static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
+	struct opal_msg msg;
+	int psr, ret, token;
+
+	ret = kstrtoint(buf, 0, &psr);
+	if (ret)
+		return ret;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&psr_mutex);
+	ret = opal_set_power_shifting_ratio(psr_attr->handle, token, psr);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = count;
+		break;
+	case OPAL_SUCCESS:
+		ret = count;
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&psr_mutex);
+	opal_async_release_token(token);
+
+	return ret;
+}
+
+void __init opal_psr_init(void)
+{
+	struct device_node *psr, *node;
+	int psr_attr_count = 0, i = 0;
+
+	psr = of_find_node_by_path("/ibm,opal/power-mgt/psr");
+	if (!psr) {
+		pr_devel("/ibm,opal/power-mgt/psr node not found\n");
+		return;
+	}
+
+	for_each_child_of_node(psr, node)
+		psr_attr_count++;
+
+	psr_attrs = kcalloc(psr_attr_count, sizeof(struct psr_attr),
+			    GFP_KERNEL);
+	if (!psr_attrs)
+		return;
+
+	for_each_child_of_node(psr, node) {
+		if (of_property_read_u32(node, "handle",
+					 &psr_attrs[i].handle))
+			goto out;
+
+		sysfs_attr_init(&psr_attrs[i].attr.attr);
+		if (of_property_read_string(node, "label",
+					    &psr_attrs[i].attr.attr.name))
+			goto out;
+		psr_attrs[i].attr.attr.mode = 0664;
+		psr_attrs[i].attr.show = psr_show;
+		psr_attrs[i].attr.store = psr_store;
+		i++;
+	}
+
+	psr_kobj = kobject_create_and_add("psr", opal_kobj);
+	if (!psr_kobj) {
+		pr_warn("Failed to create psr kobkect\n");
+		goto out;
+	}
+
+	for (i = 0; i < psr_attr_count; i++)
+		if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
+			pr_devel("Failed to create sysfs file %s\n",
+				 psr_attrs[i].attr.attr.name);
+			goto out_kobj;
+		}
+
+	return;
+out_kobj:
+	kobject_put(psr_kobj);
+out:
+	kfree(psr_attrs);
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index eff5fe7..9867726 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -312,3 +312,5 @@ OPAL_CALL(opal_npu_destroy_context,		OPAL_NPU_DESTROY_CONTEXT);
 OPAL_CALL(opal_npu_map_lpar,			OPAL_NPU_MAP_LPAR);
 OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
 OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
+OPAL_CALL(opal_get_power_shifting_ratio,	OPAL_GET_PSR);
+OPAL_CALL(opal_set_power_shifting_ratio,	OPAL_SET_PSR);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 889da97..280a736 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -839,6 +839,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL powercap interface */
 	opal_powercap_init();
 
+	/* Initialise OPAL Power-Shifting-Ratio interface */
+	opal_psr_init();
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
-- 
1.8.3.1

Re: [PATCH V8 1/3] powernv: powercap: Add support for powercap framework

From: Cyril Bur <hidden>
Date: 2017-07-28 01:39:43

On Wed, 2017-07-26 at 10:35 +0530, Shilpasri G Bhat wrote:
quoted hunk
Adds a generic powercap framework to change the system powercap
inband through OPAL-OCC command/response interface.

Signed-off-by: Shilpasri G Bhat <redacted>
---
Changes from V7:
- Replaced sscanf with kstrtoint

 arch/powerpc/include/asm/opal-api.h            |   5 +-
 arch/powerpc/include/asm/opal.h                |   4 +
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-powercap.c | 237 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +
 arch/powerpc/platforms/powernv/opal.c          |   4 +
 6 files changed, 252 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-powercap.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 3130a73..c3e0c4a 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -42,6 +42,7 @@
 #define OPAL_I2C_STOP_ERR	-24
 #define OPAL_XIVE_PROVISIONING	-31
 #define OPAL_XIVE_FREE_ACTIVE	-32
+#define OPAL_TIMEOUT		-33
 
 /* API Tokens (in r0) */
 #define OPAL_INVALID_CALL		       -1
@@ -190,7 +191,9 @@
 #define OPAL_NPU_INIT_CONTEXT			146
 #define OPAL_NPU_DESTROY_CONTEXT		147
 #define OPAL_NPU_MAP_LPAR			148
-#define OPAL_LAST				148
+#define OPAL_GET_POWERCAP			152
+#define OPAL_SET_POWERCAP			153
+#define OPAL_LAST				153
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 588fb1c..ec2087c 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -267,6 +267,8 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int64_t opal_xive_free_irq(uint32_t girq);
 int64_t opal_xive_sync(uint32_t type, uint32_t id);
 int64_t opal_xive_dump(uint32_t type, uint32_t id);
+int opal_get_powercap(u32 handle, int token, u32 *pcap);
+int opal_set_powercap(u32 handle, int token, u32 pcap);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -345,6 +347,8 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 
 void opal_wake_poller(void);
 
+void opal_powercap_init(void);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* _ASM_POWERPC_OPAL_H */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index b5d98cb..e79f806 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o
+obj-y			+= opal-kmsg.o opal-powercap.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-powercap.c b/arch/powerpc/platforms/powernv/opal-powercap.c
new file mode 100644
index 0000000..7c57f4b
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-powercap.c
@@ -0,0 +1,237 @@
+/*
+ * PowerNV OPAL Powercap interface
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt)     "opal-powercap: " fmt
+
+#include <linux/of.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include <asm/opal.h>
+
+DEFINE_MUTEX(powercap_mutex);
+
+static struct kobject *powercap_kobj;
+
+struct powercap_attr {
+	u32 handle;
+	struct kobj_attribute attr;
+};
+
+static struct attribute_group *pattr_groups;
+static struct powercap_attr *pcap_attrs;
+
+static ssize_t powercap_show(struct kobject *kobj, struct kobj_attribute *attr,
+			     char *buf)
+{
+	struct powercap_attr *pcap_attr = container_of(attr,
+						struct powercap_attr, attr);
+	struct opal_msg msg;
+	u32 pcap;
+	int ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&powercap_mutex);
If this is purely a userspace interface, shouldn't this be
mutex_lock_interruptible()?

I'm going to say that we should leave this but I am curious as to what
it is protecting.

This is more for MPE and Stewart:
If there is some mutual exclusion that needs to happen, it should be
done in skiboot. We've had problems in the past with double entering
skiboot and hard to interpret errors ending up in userspace, this
solves that but it seems more like a coverup than an actual solution.
+	ret = opal_get_powercap(pcap_attr->handle, token, &pcap);
Should always pass physical address of pointers to skiboot __pa(&pcap)
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
This comment has nothing to do with this patch but this code would
benefit quite directly from opal_async_wait_response_interruptible()
that I've been working on.
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
I wonder if the ret from opal_async_wait_response() is the best value
to return to userspace here. opal_async_wait_response() will return
-EINVAL if anything goes wrong, that feels confusing, perhaps -EIO.
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
I expect that for this and the OPAL_SUCCESS case you'll want to check
that ret is not negative, if it is you'll probably also want to return
-EIO or something reasonable.

I have no idea what the values are, what units they're in or anything -
 I assume %u is what makes the most sense since this should just be a
number.
+		break;
+	case OPAL_SUCCESS:
+		ret = sprintf(buf, "%u\n", be32_to_cpu(pcap));
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&powercap_mutex);
+	opal_async_release_token(token);
+	return ret;
+}
+
+static ssize_t powercap_store(struct kobject *kobj,
+			      struct kobj_attribute *attr, const char *buf,
+			      size_t count)
+{
+	struct powercap_attr *pcap_attr = container_of(attr,
+						struct powercap_attr, attr);
+	struct opal_msg msg;
+	u32 pcap;
+	int ret, token;
+
+	ret = kstrtoint(buf, 0, &pcap);
+	if (ret)
+		return ret;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&powercap_mutex);
+	ret = opal_set_powercap(pcap_attr->handle, token, pcap);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = count;
+		break;
+	case OPAL_SUCCESS:
+		ret = count;
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&powercap_mutex);
+	opal_async_release_token(token);
+
+	return ret;
+}
+
+static void powercap_add_attr(int handle, const char *name,
+			      struct powercap_attr *attr)
+{
+	attr->handle = handle;
+	sysfs_attr_init(&attr->attr.attr);
+	attr->attr.attr.name = name;
+	attr->attr.attr.mode = 0444;
+	attr->attr.show = powercap_show;
+}
+
+void __init opal_powercap_init(void)
+{
+	struct device_node *powercap, *node;
+	int pattr_group_count = 0, total_attr_count = 0;
+	int i, count;
+
+	powercap = of_find_node_by_path("/ibm,opal/power-mgt/powercap");
+	if (!powercap) {
+		pr_devel("/ibm,opal/power-mgt/powercap node not found\n");
+		return;
+	}
+
+	for_each_child_of_node(powercap, node)
So I went digging and found this: of_get_child_count() which I think is
what you want (I'm always in favour of using generic helpers), then I
saw this right below it of_get_available_child_count(), do we care?
+		pattr_group_count++;
+
+	pattr_groups = kcalloc(pattr_group_count,
+			       sizeof(struct attribute_group), GFP_KERNEL);
+	if (!pattr_groups)
+		return;
+
+	i = 0;
+	for_each_child_of_node(powercap, node) {
+		int attr_count = 0;
+
+		if (of_find_property(node, "powercap-min", NULL))
+			attr_count++;
+		if (of_find_property(node, "powercap-max", NULL))
+			attr_count++;
+		if (of_find_property(node, "powercap-cur", NULL))
+			attr_count++;
+
+		total_attr_count += attr_count;
+		pattr_groups[i].attrs = kcalloc(attr_count + 1,
+						sizeof(struct attribute *),
+						GFP_KERNEL);
+		if (!pattr_groups[i].attrs) {
+			while (--i >= 0)
+				kfree(pattr_groups[i].attrs);
+			goto out_pattr_groups;
+		}
+		i++;
+	}
+
+	pcap_attrs = kcalloc(total_attr_count, sizeof(struct powercap_attr),
+			     GFP_KERNEL);
+	if (!pcap_attrs)
+		goto out_pattr_groups_attrs;
Is there any reason that pcap_attrs needs to be contiguous? If not, I
feel like you could eliminate the entire loop below (and the last one
as well maybe) and just do the assignment of pattr_groups[].attrs[] up
there.

In fact do you even need to store pcap_attrs? If you kcalloc them as
you need them (in the loop above), you can always free them again on
error by freeing pattr_groups[].attrs[] right?

I'll admit I've become quite confused as to the layout of the sysfs dir
 that you're creating here - would you mind showing what the expected
layout will be?

I'll take more of a look once thats more clear in my head

Thanks,

Cyril
quoted hunk
+
+	count = 0;
+	i = 0;
+	for_each_child_of_node(powercap, node) {
+		u32 handle;
+		int j = 0;
+
+		pattr_groups[i].name = node->name;
+
+		if (!of_property_read_u32(node, "powercap-min", &handle)) {
+			powercap_add_attr(handle, "powercap-min",
+					  &pcap_attrs[count]);
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+
+		if (!of_property_read_u32(node, "powercap-max", &handle)) {
+			powercap_add_attr(handle, "powercap-max",
+					  &pcap_attrs[count]);
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+
+		if (!of_property_read_u32(node, "powercap-cur", &handle)) {
+			powercap_add_attr(handle, "powercap-cur",
+					  &pcap_attrs[count]);
+			pcap_attrs[count].attr.attr.mode |= 0220;
+			pcap_attrs[count].attr.store = powercap_store;
+			pattr_groups[i].attrs[j++] =
+				&pcap_attrs[count++].attr.attr;
+		}
+		i++;
+	}
+
+	powercap_kobj = kobject_create_and_add("powercap", opal_kobj);
+	if (!powercap_kobj) {
+		pr_warn("Failed to create powercap kobject\n");
+		goto out_pcap_attrs;
+	}
+
+	for (i = 0; i < pattr_group_count; i++) {
+		if (sysfs_create_group(powercap_kobj, &pattr_groups[i])) {
+			pr_warn("Failed to create powercap attribute group %s\n",
+				pattr_groups[i].name);
+			goto out;
+		}
+	}
+
+	return;
+out:
+	kobject_put(powercap_kobj);
+out_pcap_attrs:
+	kfree(pcap_attrs);
+out_pattr_groups_attrs:
+	while (--pattr_group_count >= 0)
+		kfree(pattr_groups[i].attrs);
+out_pattr_groups:
+	kfree(pattr_groups);
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 4ca6c26..eff5fe7 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -310,3 +310,5 @@ OPAL_CALL(opal_xive_dump,			OPAL_XIVE_DUMP);
 OPAL_CALL(opal_npu_init_context,		OPAL_NPU_INIT_CONTEXT);
 OPAL_CALL(opal_npu_destroy_context,		OPAL_NPU_DESTROY_CONTEXT);
 OPAL_CALL(opal_npu_map_lpar,			OPAL_NPU_MAP_LPAR);
+OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
+OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index cad6b57..889da97 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -836,6 +836,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL kmsg dumper for flushing console on panic */
 	opal_kmsg_init();
 
+	/* Initialise OPAL powercap interface */
+	opal_powercap_init();
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);
@@ -952,6 +955,7 @@ int opal_error_code(int rc)
 	case OPAL_UNSUPPORTED:		return -EIO;
 	case OPAL_HARDWARE:		return -EIO;
 	case OPAL_INTERNAL_ERROR:	return -EIO;
+	case OPAL_TIMEOUT:		return -ETIMEDOUT;
 	default:
 		pr_err("%s: unexpected OPAL error %d\n", __func__, rc);
 		return -EIO;

Re: [PATCH V8 1/3] powernv: powercap: Add support for powercap framework

From: Shilpasri G Bhat <hidden>
Date: 2017-07-28 04:05:56

Hi Cyril,

On 07/28/2017 07:09 AM, Cyril Bur wrote:
Is there any reason that pcap_attrs needs to be contiguous? If not, I
feel like you could eliminate the entire loop below (and the last one
as well maybe) and just do the assignment of pattr_groups[].attrs[] up
there.

In fact do you even need to store pcap_attrs? If you kcalloc them as
you need them (in the loop above), you can always free them again on
error by freeing pattr_groups[].attrs[] right?

I'll admit I've become quite confused as to the layout of the sysfs dir
 that you're creating here - would you mind showing what the expected
layout will be?

I'll take more of a look once thats more clear in my head

Thanks,

Cyril
The sysfs layout looks as below:
# ls /sys/firmware/opal/powercap/
system-powercap

# ls /sys/firmware/opal/powercap/system-powercap/
powercap-current  powercap-max  powercap-min

# grep .  /sys/firmware/opal/powercap/system-powercap/*
/sys/firmware/opal/powercap/system-powercap/powercap-current:2375
/sys/firmware/opal/powercap/system-powercap/powercap-max:2375
/sys/firmware/opal/powercap/system-powercap/powercap-min:1945

Thanks and Regards,
Shilpa

Re: [PATCH V8 2/3] powernv: Add support to set power-shifting-ratio

From: Cyril Bur <hidden>
Date: 2017-07-28 04:15:51

On Wed, 2017-07-26 at 10:35 +0530, Shilpasri G Bhat wrote:
This patch adds support to set power-shifting-ratio for CPU-GPU which
is used by OCC power capping algorithm.

Signed-off-by: Shilpasri G Bhat <redacted>

Hi Shilpasri,

I started looking though this - a lot the comments to patch 1/3 apply
here so I'll stop repeating myself :).


Thanks,

Cyril
quoted hunk
---
Changes from V7:
- Replaced sscanf with kstrtoint

 arch/powerpc/include/asm/opal-api.h            |   4 +-
 arch/powerpc/include/asm/opal.h                |   3 +
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-psr.c      | 169 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   2 +
 arch/powerpc/platforms/powernv/opal.c          |   3 +
 6 files changed, 181 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/platforms/powernv/opal-psr.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index c3e0c4a..0d37315 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -193,7 +193,9 @@
 #define OPAL_NPU_MAP_LPAR			148
 #define OPAL_GET_POWERCAP			152
 #define OPAL_SET_POWERCAP			153
-#define OPAL_LAST				153
+#define OPAL_GET_PSR				154
+#define OPAL_SET_PSR				155
+#define OPAL_LAST				155
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index ec2087c..58b30a4 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -269,6 +269,8 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int64_t opal_xive_dump(uint32_t type, uint32_t id);
 int opal_get_powercap(u32 handle, int token, u32 *pcap);
 int opal_set_powercap(u32 handle, int token, u32 pcap);
+int opal_get_power_shifting_ratio(u32 handle, int token, u32 *psr);
+int opal_set_power_shifting_ratio(u32 handle, int token, u32 psr);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -348,6 +350,7 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 void opal_wake_poller(void);
 
 void opal_powercap_init(void);
+void opal_psr_init(void);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index e79f806..9ed7d33 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o opal-powercap.o
+obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-psr.c b/arch/powerpc/platforms/powernv/opal-psr.c
new file mode 100644
index 0000000..07e3f78
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-psr.c
@@ -0,0 +1,169 @@
+/*
+ * PowerNV OPAL Power-Shifting-Ratio interface
+ *
+ * Copyright 2017 IBM Corp.
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version
+ * 2 of the License, or (at your option) any later version.
+ */
+
+#define pr_fmt(fmt)     "opal-psr: " fmt
+
+#include <linux/of.h>
+#include <linux/kobject.h>
+#include <linux/slab.h>
+
+#include <asm/opal.h>
+
+DEFINE_MUTEX(psr_mutex);
+
+static struct kobject *psr_kobj;
+
+struct psr_attr {
+	u32 handle;
+	struct kobj_attribute attr;
+};
+
+static struct psr_attr *psr_attrs;
+static struct kobject *psr_kobj;
+
+static ssize_t psr_show(struct kobject *kobj, struct kobj_attribute *attr,
+			char *buf)
+{
+	struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
+	struct opal_msg msg;
+	int psr, ret, token;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&psr_mutex);
+	ret = opal_get_power_shifting_ratio(psr_attr->handle, token, &psr);
__pa()
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
+		break;
+	case OPAL_SUCCESS:
+		ret = sprintf(buf, "%u\n", be32_to_cpu(psr));
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&psr_mutex);
+	opal_async_release_token(token);
Same comment as previous patch - I don't know if returning the -EINVAL
from opal_async_wait_response()... we should probably start deciding at
a higher level what to do...
+	return ret;
+}
+
+static ssize_t psr_store(struct kobject *kobj, struct kobj_attribute *attr,
+			 const char *buf, size_t count)
+{
+	struct psr_attr *psr_attr = container_of(attr, struct psr_attr, attr);
+	struct opal_msg msg;
+	int psr, ret, token;
+
+	ret = kstrtoint(buf, 0, &psr);
+	if (ret)
+		return ret;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get token\n");
+		return token;
+	}
+
+	mutex_lock(&psr_mutex);
+	ret = opal_set_power_shifting_ratio(psr_attr->handle, token, psr);
+	switch (ret) {
+	case OPAL_ASYNC_COMPLETION:
+		ret = opal_async_wait_response(token, &msg);
+		if (ret) {
+			pr_devel("Failed to wait for the async response %d\n",
+				 ret);
+			goto out;
+		}
+		ret = opal_error_code(opal_get_async_rc(msg));
+		if (!ret)
+			ret = count;
+		break;
+	case OPAL_SUCCESS:
+		ret = count;
+		break;
+	default:
+		ret = opal_error_code(ret);
+	}
+
+out:
+	mutex_unlock(&psr_mutex);
+	opal_async_release_token(token);
+
+	return ret;
+}
+
+void __init opal_psr_init(void)
+{
+	struct device_node *psr, *node;
+	int psr_attr_count = 0, i = 0;
+
+	psr = of_find_node_by_path("/ibm,opal/power-mgt/psr");
+	if (!psr) {
+		pr_devel("/ibm,opal/power-mgt/psr node not found\n");
+		return;
+	}
+
+	for_each_child_of_node(psr, node)
+		psr_attr_count++;
+
+	psr_attrs = kcalloc(psr_attr_count, sizeof(struct psr_attr),
+			    GFP_KERNEL);
+	if (!psr_attrs)
+		return;
+
+	for_each_child_of_node(psr, node) {
+		if (of_property_read_u32(node, "handle",
+					 &psr_attrs[i].handle))
+			goto out;
+
+		sysfs_attr_init(&psr_attrs[i].attr.attr);
+		if (of_property_read_string(node, "label",
+					    &psr_attrs[i].attr.attr.name))
+			goto out;
+		psr_attrs[i].attr.attr.mode = 0664;
+		psr_attrs[i].attr.show = psr_show;
+		psr_attrs[i].attr.store = psr_store;
+		i++;
+	}
+
+	psr_kobj = kobject_create_and_add("psr", opal_kobj);
+	if (!psr_kobj) {
+		pr_warn("Failed to create psr kobkect\n");
Typo
+		goto out;
+	}
+
+	for (i = 0; i < psr_attr_count; i++)
+		if (sysfs_create_file(psr_kobj, &psr_attrs[i].attr.attr)) {
+			pr_devel("Failed to create sysfs file %s\n",
+				 psr_attrs[i].attr.attr.name);
+			goto out_kobj;
+
Can't we do all that in the first loop?
quoted hunk
		}
+
+	return;
+out_kobj:
+	kobject_put(psr_kobj);
+out:
+	kfree(psr_attrs);
+}
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index eff5fe7..9867726 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -312,3 +312,5 @@ OPAL_CALL(opal_npu_destroy_context,		OPAL_NPU_DESTROY_CONTEXT);
 OPAL_CALL(opal_npu_map_lpar,			OPAL_NPU_MAP_LPAR);
 OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
 OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
+OPAL_CALL(opal_get_power_shifting_ratio,	OPAL_GET_PSR);
+OPAL_CALL(opal_set_power_shifting_ratio,	OPAL_SET_PSR);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 889da97..280a736 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -839,6 +839,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL powercap interface */
 	opal_powercap_init();
 
+	/* Initialise OPAL Power-Shifting-Ratio interface */
+	opal_psr_init();
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);

Re: [PATCH V8 3/3] powernv: Add support to clear sensor groups data

From: Cyril Bur <hidden>
Date: 2017-07-28 04:39:25

On Wed, 2017-07-26 at 10:35 +0530, Shilpasri G Bhat wrote:
Adds support for clearing different sensor groups. OCC inband sensor
groups like CSM, Profiler, Job Scheduler can be cleared using this
driver. The min/max of all sensors belonging to these sensor groups
will be cleared.
Hi Shilpasri,

I think also some comments from v1 also apply here.

Other comments inline

Thanks,

Cyril
quoted hunk
Signed-off-by: Shilpasri G Bhat <redacted>
---
Changes from V7:
- s/send_occ_command/opal_sensor_groups_clear_history

 arch/powerpc/include/asm/opal-api.h            |   3 +-
 arch/powerpc/include/asm/opal.h                |   2 +
 arch/powerpc/include/uapi/asm/opal-occ.h       |  23 ++++++
 arch/powerpc/platforms/powernv/Makefile        |   2 +-
 arch/powerpc/platforms/powernv/opal-occ.c      | 109 +++++++++++++++++++++++++
 arch/powerpc/platforms/powernv/opal-wrappers.S |   1 +
 arch/powerpc/platforms/powernv/opal.c          |   3 +
 7 files changed, 141 insertions(+), 2 deletions(-)
 create mode 100644 arch/powerpc/include/uapi/asm/opal-occ.h
 create mode 100644 arch/powerpc/platforms/powernv/opal-occ.c
diff --git a/arch/powerpc/include/asm/opal-api.h b/arch/powerpc/include/asm/opal-api.h
index 0d37315..342738a 100644
--- a/arch/powerpc/include/asm/opal-api.h
+++ b/arch/powerpc/include/asm/opal-api.h
@@ -195,7 +195,8 @@
 #define OPAL_SET_POWERCAP			153
 #define OPAL_GET_PSR				154
 #define OPAL_SET_PSR				155
-#define OPAL_LAST				155
+#define OPAL_SENSOR_GROUPS_CLEAR		156
+#define OPAL_LAST				156
 
 /* Device tree flags */
 
diff --git a/arch/powerpc/include/asm/opal.h b/arch/powerpc/include/asm/opal.h
index 58b30a4..92db6af 100644
--- a/arch/powerpc/include/asm/opal.h
+++ b/arch/powerpc/include/asm/opal.h
@@ -271,6 +271,7 @@ int64_t opal_xive_set_vp_info(uint64_t vp,
 int opal_set_powercap(u32 handle, int token, u32 pcap);
 int opal_get_power_shifting_ratio(u32 handle, int token, u32 *psr);
 int opal_set_power_shifting_ratio(u32 handle, int token, u32 psr);
+int opal_sensor_groups_clear(u32 group_hndl, int token);
 
 /* Internal functions */
 extern int early_init_dt_scan_opal(unsigned long node, const char *uname,
@@ -351,6 +352,7 @@ static inline int opal_get_async_rc(struct opal_msg msg)
 
 void opal_powercap_init(void);
 void opal_psr_init(void);
+int opal_sensor_groups_clear_history(u32 handle);
 
 #endif /* __ASSEMBLY__ */
 
diff --git a/arch/powerpc/include/uapi/asm/opal-occ.h b/arch/powerpc/include/uapi/asm/opal-occ.h
new file mode 100644
index 0000000..97c45e2
--- /dev/null
+++ b/arch/powerpc/include/uapi/asm/opal-occ.h
@@ -0,0 +1,23 @@
+/*
+ * OPAL OCC command interface
+ * Supported on POWERNV platform
+ *
+ * (C) Copyright IBM 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License as published by
+ * the Free Software Foundation; either version 2, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#ifndef _UAPI_ASM_POWERPC_OPAL_OCC_H_
+#define _UAPI_ASM_POWERPC_OPAL_OCC_H_
+
+#define OPAL_OCC_IOCTL_CLEAR_SENSOR_GROUPS	_IOR('o', 1, u32)
+
+#endif /* _UAPI_ASM_POWERPC_OPAL_OCC_H */
diff --git a/arch/powerpc/platforms/powernv/Makefile b/arch/powerpc/platforms/powernv/Makefile
index 9ed7d33..f193b33 100644
--- a/arch/powerpc/platforms/powernv/Makefile
+++ b/arch/powerpc/platforms/powernv/Makefile
@@ -2,7 +2,7 @@ obj-y			+= setup.o opal-wrappers.o opal.o opal-async.o idle.o
 obj-y			+= opal-rtc.o opal-nvram.o opal-lpc.o opal-flash.o
 obj-y			+= rng.o opal-elog.o opal-dump.o opal-sysparam.o opal-sensor.o
 obj-y			+= opal-msglog.o opal-hmi.o opal-power.o opal-irqchip.o
-obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o
+obj-y			+= opal-kmsg.o opal-powercap.o opal-psr.o opal-occ.o
 
 obj-$(CONFIG_SMP)	+= smp.o subcore.o subcore-asm.o
 obj-$(CONFIG_PCI)	+= pci.o pci-ioda.o npu-dma.o
diff --git a/arch/powerpc/platforms/powernv/opal-occ.c b/arch/powerpc/platforms/powernv/opal-occ.c
new file mode 100644
index 0000000..d1d4b28
--- /dev/null
+++ b/arch/powerpc/platforms/powernv/opal-occ.c
@@ -0,0 +1,109 @@
+/*
+ * Copyright IBM Corporation 2017
+ *
+ * This program is free software; you can redistribute it and/or modify
+ * it under the terms of the GNU General Public License version 2 as
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that 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.
+ */
+
+#define pr_fmt(fmt) "opal-occ: " fmt
+
+#include <linux/kernel.h>
+#include <linux/module.h>
+#include <linux/platform_device.h>
+#include <linux/miscdevice.h>
+#include <linux/fs.h>
+#include <asm/opal.h>
+#include <asm/opal-occ.h>
+
+DEFINE_MUTEX(opal_occ_mutex);
+
+int opal_sensor_groups_clear_history(u32 handle)
+{
+	struct opal_msg async_msg;
+	int token, rc;
+
+	token = opal_async_get_token_interruptible();
+	if (token < 0) {
+		pr_devel("Failed to get the token %d\n", token);
+		return token;
+	}
+
+	mutex_lock(&opal_occ_mutex);
+	rc = opal_sensor_groups_clear(handle, token);
+	if (rc == OPAL_ASYNC_COMPLETION) {
+		rc = opal_async_wait_response(token, &async_msg);
+		if (rc) {
rc here is an errno, but you're going to pass it through
opal_error_code() before returning
+			pr_devel("Failed to wait for async response %d\n", rc);
+			goto out;
+		}
+		rc = opal_get_async_rc(async_msg);
+	}
+out:
+	mutex_unlock(&opal_occ_mutex);
+	opal_async_release_token(token);
+	return opal_error_code(rc);
+}
+EXPORT_SYMBOL_GPL(opal_sensor_groups_clear_history);
+
+static long opal_occ_ioctl(struct file *file, unsigned int cmd,
+			   unsigned long param)
+{
+	int rc = -EINVAL;
+
+	switch (cmd) {
+	case OPAL_OCC_IOCTL_CLEAR_SENSOR_GROUPS:
+		rc = opal_sensor_groups_clear_history(param);
+		break;
+	default:
+		break;
+	}
+
+	return rc;
+}
+
+static const struct file_operations opal_occ_fops = {
+	.unlocked_ioctl = opal_occ_ioctl,
So is there a plan I'm missing to get a file descriptor to be able to
actually call ioctl()?
+	.owner		= THIS_MODULE,
+};
+
+static struct miscdevice occ_dev = {
+	.minor	= MISC_DYNAMIC_MINOR,
+	.name	= "occ",
+	.fops	= &opal_occ_fops,
+};
+
+static int opal_occ_probe(struct platform_device *pdev)
+{
+	return misc_register(&occ_dev);
+}
+
+static int opal_occ_remove(struct platform_device *pdev)
+{
Is it possible to race the _remove() with the _ioctl()? Presumably not
if theres an open fd... surely its fine.
quoted hunk
+	misc_deregister(&occ_dev);
+	return 0;
+}
+
+static const struct of_device_id opal_occ_match[] = {
+	{ .compatible = "ibm,opal-occ-sensor-group" },
+	{ },
+};
+
+static struct platform_driver opal_occ_driver = {
+	.driver = {
+		.name           = "opal-occ",
+		.of_match_table = opal_occ_match,
+	},
+	.probe	= opal_occ_probe,
+	.remove	= opal_occ_remove,
+};
+
+module_platform_driver(opal_occ_driver);
+
+MODULE_DESCRIPTION("PowerNV OPAL-OCC driver");
+MODULE_LICENSE("GPL");
diff --git a/arch/powerpc/platforms/powernv/opal-wrappers.S b/arch/powerpc/platforms/powernv/opal-wrappers.S
index 9867726..c1130e8 100644
--- a/arch/powerpc/platforms/powernv/opal-wrappers.S
+++ b/arch/powerpc/platforms/powernv/opal-wrappers.S
@@ -314,3 +314,4 @@ OPAL_CALL(opal_get_powercap,			OPAL_GET_POWERCAP);
 OPAL_CALL(opal_set_powercap,			OPAL_SET_POWERCAP);
 OPAL_CALL(opal_get_power_shifting_ratio,	OPAL_GET_PSR);
 OPAL_CALL(opal_set_power_shifting_ratio,	OPAL_SET_PSR);
+OPAL_CALL(opal_sensor_groups_clear,		OPAL_SENSOR_GROUPS_CLEAR);
diff --git a/arch/powerpc/platforms/powernv/opal.c b/arch/powerpc/platforms/powernv/opal.c
index 280a736..097c33c 100644
--- a/arch/powerpc/platforms/powernv/opal.c
+++ b/arch/powerpc/platforms/powernv/opal.c
@@ -842,6 +842,9 @@ static int __init opal_init(void)
 	/* Initialise OPAL Power-Shifting-Ratio interface */
 	opal_psr_init();
 
+	/* Initialize platform device: OCC interface */
+	opal_pdev_init("ibm,opal-occ-sensor-group");
+
 	return 0;
 }
 machine_subsys_initcall(powernv, opal_init);

Re: [PATCH V8 1/3] powernv: powercap: Add support for powercap framework

From: Stewart Smith <hidden>
Date: 2017-07-28 07:19:09

Cyril Bur [off-list ref] writes:
This is more for MPE and Stewart:
If there is some mutual exclusion that needs to happen, it should be
done in skiboot. We've had problems in the past with double entering
skiboot and hard to interpret errors ending up in userspace, this
solves that but it seems more like a coverup than an actual solution.
Yeah, I'd like us to be in a position where we don't force mutual
exclusion on such things out to the OS.

The real issue this papers over is the async token stuff you're
reworking. There's that, plus for this specific thing, you *could* go
and set a differnt powercap 180 times concurrently and we should do the
right thing in skiboot... but then you're sitting in skiboot rather than
sitting in linux being able to go run some other task on the thread.

-- 
Stewart Smith
OPAL Architect, IBM.
Keyboard shortcuts
hback out one level
jnext message in thread
kprevious message in thread
ldrill in
Escclose help / fold thread tree
?toggle this help