[Skiboot] [PATCH V9 3/8] powercap: occ: Add a generic powercap framework

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Fri Jul 28 05:15:28 AEST 2017


This patch adds a generic powercap framework and exports OCC powercap
sensors using which system powercap can be set inband through OPAL-OCC
command-response interface.

Documentation for powercap enhanced by Stewart Smith.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from V8:
- Enhanced documentation.
- Add compatible property "ibm,opal-powercap"
- Return OPAL_PERMISSION on setting powercap-{min/max}
- s/powercap-cur/powercap-current

 core/Makefile.inc                               |   2 +-
 core/powercap.c                                 |  40 ++++++++
 doc/device-tree/ibm,opal/power-mgt/powercap.rst |  48 ++++++++++
 doc/opal-api/opal-powercap.rst                  |  96 +++++++++++++++++++
 hw/occ.c                                        | 119 +++++++++++++++++++++++-
 include/opal-api.h                              |   4 +-
 include/powercap.h                              |  43 +++++++++
 7 files changed, 348 insertions(+), 4 deletions(-)
 create mode 100644 core/powercap.c
 create mode 100644 doc/device-tree/ibm,opal/power-mgt/powercap.rst
 create mode 100644 doc/opal-api/opal-powercap.rst
 create mode 100644 include/powercap.h

diff --git a/core/Makefile.inc b/core/Makefile.inc
index b09c30c..b3c9e91 100644
--- a/core/Makefile.inc
+++ b/core/Makefile.inc
@@ -8,7 +8,7 @@ CORE_OBJS += pci-opal.o fast-reboot.o device.o exceptions.o trace.o affinity.o
 CORE_OBJS += vpd.o hostservices.o platform.o nvram.o nvram-format.o hmi.o
 CORE_OBJS += console-log.o ipmi.o time-utils.o pel.o pool.o errorlog.o
 CORE_OBJS += timer.o i2c.o rtc.o flash.o sensor.o ipmi-opal.o
-CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o
+CORE_OBJS += flash-subpartition.o bitmap.o buddy.o pci-quirk.o powercap.o
 
 ifeq ($(SKIBOOT_GCOV),1)
 CORE_OBJS += gcov-profiling.o
diff --git a/core/powercap.c b/core/powercap.c
new file mode 100644
index 0000000..50b5996
--- /dev/null
+++ b/core/powercap.c
@@ -0,0 +1,40 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#include <powercap.h>
+
+static int opal_get_powercap(u32 handle, int token __unused, u32 *pcap)
+{
+	if (!pcap || !opal_addr_valid(pcap))
+		return OPAL_PARAMETER;
+
+	if (powercap_get_class(handle) == POWERCAP_CLASS_OCC)
+		return occ_get_powercap(handle, pcap);
+
+	return OPAL_UNSUPPORTED;
+};
+
+opal_call(OPAL_GET_POWERCAP, opal_get_powercap, 3);
+
+static int opal_set_powercap(u32 handle, int token, u32 pcap)
+{
+	if (powercap_get_class(handle) == POWERCAP_CLASS_OCC)
+		return occ_set_powercap(handle, token, pcap);
+
+	return OPAL_UNSUPPORTED;
+};
+
+opal_call(OPAL_SET_POWERCAP, opal_set_powercap, 3);
diff --git a/doc/device-tree/ibm,opal/power-mgt/powercap.rst b/doc/device-tree/ibm,opal/power-mgt/powercap.rst
new file mode 100644
index 0000000..e47caa4
--- /dev/null
+++ b/doc/device-tree/ibm,opal/power-mgt/powercap.rst
@@ -0,0 +1,48 @@
+power-mgt/powercap
+------------------
+
+The powercap sensors are populated in this node. Each child node in
+the "powercap" node represents a power-cappable component.
+
+For example : ::
+        system-powercap/
+
+The OPAL_GET_POWERCAP and OPAL_SET_POWERCAP calls take a handle for
+what powercap property to get/set which is defined in the child node.
+
+The compatible property for the linux driver which will be
+"ibm,opal-powercap"
+
+Each child node has below properties:
+
+`powercap-current`
+  Handle to indicate the current powercap
+
+`powercap-min`
+  Minimum possible powercap
+
+`powercap-max`
+  Maximum possible powercap
+
+Powercap handle uses the following encoding: ::
+
+        | Class |    Reserved   | Attribute |
+        |-------|---------------|-----------|
+
+Note: The format of the powercap handle is ``NOT`` ABI and may change in
+the future.
+
+.. code-block:: dts
+
+   power-mgt {
+     powercap {
+        compatible = "ibm,opal-powercap";
+
+        system-powercap {
+                name = "system-powercap"
+                powercap-current = <0x00000002>
+                powercap-min = <0x00000000>
+                powercap-max = <0x00000001>
+        };
+     };
+    }
diff --git a/doc/opal-api/opal-powercap.rst b/doc/opal-api/opal-powercap.rst
new file mode 100644
index 0000000..00f6866
--- /dev/null
+++ b/doc/opal-api/opal-powercap.rst
@@ -0,0 +1,96 @@
+.. _opal-powercap:
+
+OPAL_GET_POWERCAP
+==================
+The OPAL_GET_POWERCAP call retreives current information on the power
+cap.
+
+For each entity that can be power capped, the device tree
+binding indicates what handle should be passed for each of the power cap
+properties (minimum possible, maximum possible, current powercap).
+
+The current power cap must be between the minimium possible and maximum
+possible power cap. The minimum and maximum values are dynamic to allow
+for them possibly being changed by other factors or entities
+(e.g. service processor).
+
+The call can be asynchronus, where the token parameter is used to wait
+for the completion.
+
+Parameters
+----------
+::
+        u32 handle
+        int token
+        u32 *pcap
+
+Returns
+-------
+OPAL_SUCCESS
+  Success
+
+OPAL_PARAMETER
+  Invalid pcap pointer
+
+OPAL_UNSUPPORTED
+  No support for reading powercap sensor
+
+OPAL_HARDWARE
+  Unable to procced due to the current hardware state
+
+OPAL_ASYNC_COMPLETION
+  Request was sent and an async completion message will be sent with
+  token and status of the request.
+
+OPAL_SET_POWERCAP
+============================
+The OPAL_SET_POWERCAP call sets a power cap.
+
+For each entity that can be power capped, the device tree
+binding indicates what handle should be passed for each of the power cap
+properties (minimum possible, maximum possible, current powercap).
+
+The current power cap must be between the minimium possible and maximum
+possible power cap.
+
+You cannot currently set the minimum or maximum power cap, and thus
+OPAL_PERMISSION will be returned if it is attempted to set. In the
+future, this may change - but for now, the correct behaviour for an
+Operating System is to not attempt to set them.
+
+Parameters
+----------
+::
+        u32 handle
+        int token
+        u32 pcap
+
+Returns
+-------
+OPAL_SUCCESS
+  Success
+
+OPAL_PARAMETER
+  Invalid powercap requested beyond powercap limits
+
+OPAL_UNSUPPORTED
+  No support for changing the powercap
+
+OPAL_PERMISSION
+  Hardware cannot take the request
+
+OPAL_ASYNC_COMPLETION
+  Request was sent and an async completion message will be sent with
+  token and status of the request.
+
+OPAL_HARDWARE
+  Unable to procced due to the current hardware state
+
+OPAL_BUSY
+  Previous request in progress
+
+OPAL_INTERNAL_ERROR
+  Error in request response
+
+OPAL_TIMEOUT
+  Timeout in request completion
diff --git a/hw/occ.c b/hw/occ.c
index 58d9778..d286628 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -28,6 +28,7 @@
 #include <opal-msg.h>
 #include <timer.h>
 #include <i2c.h>
+#include <powercap.h>
 
 /* OCC Communication Area for PStates */
 
@@ -1060,8 +1061,8 @@ static int write_occ_cmd(struct cmd_interface *chip)
 	return OPAL_ASYNC_COMPLETION;
 }
 
-static int64_t __unused opal_occ_command(struct cmd_interface *chip, int token,
-					 struct opal_occ_cmd_data *cdata)
+static int64_t opal_occ_command(struct cmd_interface *chip, int token,
+				struct opal_occ_cmd_data *cdata)
 {
 	int rc;
 
@@ -1213,10 +1214,13 @@ exit:
 	unlock(&chip->queue_lock);
 }
 
+static void occ_add_powercap_sensors(struct dt_node *power_mgt);
+
 static void occ_cmd_interface_init(void)
 {
 	struct occ_dynamic_data *data;
 	struct occ_pstate_table *pdata;
+	struct dt_node *power_mgt;
 	struct proc_chip *chip;
 	int i = 0;
 
@@ -1247,8 +1251,119 @@ static void occ_cmd_interface_init(void)
 			   &chips[i]);
 		i++;
 	}
+
+	power_mgt = dt_find_by_path(dt_root, "/ibm,opal/power-mgt");
+	if (!power_mgt) {
+		prerror("OCC: dt node /ibm,opal/power-mgt not found\n");
+		return;
+	}
+
+	/* Add powercap sensors to DT */
+	occ_add_powercap_sensors(power_mgt);
+}
+
+/* Powercap interface */
+enum sensor_powercap_occ_attr {
+	POWERCAP_OCC_MIN,
+	POWERCAP_OCC_MAX,
+	POWERCAP_OCC_CUR,
+};
+
+static void occ_add_powercap_sensors(struct dt_node *power_mgt)
+{
+	struct dt_node *pcap, *node;
+	u32 handle;
+
+	pcap = dt_new(power_mgt, "powercap");
+	if (!pcap) {
+		prerror("OCC: Failed to create powercap node\n");
+		return;
+	}
+
+	dt_add_property_string(pcap, "compatible", "ibm,opal-powercap");
+	node = dt_new(pcap, "system-powercap");
+	if (!node) {
+		prerror("OCC: Failed to create system powercap node\n");
+		return;
+	}
+
+	handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_CUR);
+	dt_add_property_cells(node, "powercap-current", handle);
+
+	handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_MIN);
+	dt_add_property_cells(node, "powercap-min", handle);
+
+	handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_MAX);
+	dt_add_property_cells(node, "powercap-max", handle);
+}
+
+int occ_get_powercap(u32 handle, u32 *pcap)
+{
+	struct occ_pstate_table *pdata;
+	struct occ_dynamic_data *ddata;
+	struct proc_chip *chip;
+
+	chip = next_chip(NULL);
+	pdata = get_occ_pstate_table(chip);
+	ddata = get_occ_dynamic_data(chip);
+
+	if (!pdata->valid)
+		return OPAL_HARDWARE;
+
+	switch (powercap_get_attr(handle)) {
+	case POWERCAP_OCC_MIN:
+		*pcap = ddata->min_pwr_cap;
+		break;
+	case POWERCAP_OCC_MAX:
+		*pcap = ddata->max_pwr_cap;
+		break;
+	case POWERCAP_OCC_CUR:
+		*pcap = ddata->cur_pwr_cap;
+		break;
+	default:
+		*pcap = 0;
+		return OPAL_UNSUPPORTED;
+	}
+
+	return OPAL_SUCCESS;
 }
 
+static u16 pcap_cdata;
+static struct opal_occ_cmd_data pcap_data = {
+	.data		= (u8 *)&pcap_cdata,
+	.cmd		= OCC_CMD_SET_POWER_CAP,
+};
+
+int occ_set_powercap(u32 handle, int token, u32 pcap)
+{
+	struct occ_dynamic_data *ddata;
+	struct proc_chip *chip;
+	int i;
+
+	if (powercap_get_attr(handle) != POWERCAP_OCC_CUR)
+		return OPAL_PERMISSION;
+
+	for (i = 0; i < nr_occs; i++)
+		if (chips[i].occ_role == OCC_ROLE_MASTER)
+			break;
+
+	if (!(*chips[i].valid))
+		return OPAL_HARDWARE;
+
+	chip = get_chip(chips[i].chip_id);
+	ddata = get_occ_dynamic_data(chip);
+
+	if (pcap == ddata->cur_pwr_cap)
+		return OPAL_SUCCESS;
+
+	if (pcap && (pcap > ddata->max_pwr_cap ||
+	    pcap < ddata->min_pwr_cap))
+		return OPAL_PARAMETER;
+
+	pcap_cdata = pcap;
+	return opal_occ_command(&chips[i], token, &pcap_data);
+};
+
 /* CPU-OCC PState init */
 /* Called after OCC init on P8 and P9 */
 void occ_pstates_init(void)
diff --git a/include/opal-api.h b/include/opal-api.h
index d2137d6..3ad4898 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -208,7 +208,9 @@
 #define OPAL_IMC_COUNTERS_INIT			149
 #define OPAL_IMC_COUNTERS_START			150
 #define OPAL_IMC_COUNTERS_STOP			151
-#define OPAL_LAST				151
+#define OPAL_GET_POWERCAP			152
+#define OPAL_SET_POWERCAP			153
+#define OPAL_LAST				153
 
 /* Device tree flags */
 
diff --git a/include/powercap.h b/include/powercap.h
new file mode 100644
index 0000000..ec5e126
--- /dev/null
+++ b/include/powercap.h
@@ -0,0 +1,43 @@
+/* Copyright 2017 IBM Corp.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *	http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or
+ * implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+
+#ifndef __POWERCAP_H
+#define __POWERCAP_H
+
+#include <opal.h>
+
+enum powercap_class {
+	POWERCAP_CLASS_OCC,
+};
+
+/*
+ * Powercap handle is defined as u32. The first and last bytes are
+ * used to indicate the class and attribute.
+ *
+ *	| Class |    Reserved   | Attribute |
+ *	|-------|---------------|-----------|
+ */
+
+#define powercap_make_handle(class, attr) (((class & 0xF) << 24) | (attr & 0xF))
+
+#define powercap_get_class(handle)	((handle >> 24) & 0xF)
+#define powercap_get_attr(handle)	(handle & 0xF)
+
+/* Powercap OCC interface */
+int occ_get_powercap(u32 handle, u32 *pcap);
+int occ_set_powercap(u32 handle, int token, u32 pcap);
+
+#endif /* __POWERCAP_H */
-- 
1.8.3.1



More information about the Skiboot mailing list