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
Adds a generic powercap framework to change the system powercap
inband through OPAL-OCC command/response interface.
Signed-off-by: Shilpasri G Bhat <[email protected]>
---
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
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 <[email protected]>
---
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
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 <[email protected]>
---
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
On Wed, 2017-07-26 at 10:35 +0530, Shilpasri G Bhat wrote:
> Adds a generic powercap framework to change the system powercap
> inband through OPAL-OCC command/response interface.
>
> Signed-off-by: Shilpasri G Bhat <[email protected]>
> ---
> 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
> +
> + 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;
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
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 <[email protected]>
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
> ---
> 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?
> }
> +
> + 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);
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
> Signed-off-by: Shilpasri G Bhat <[email protected]>
> ---
> 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.
> + 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);
Cyril Bur <[email protected]> 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.