[Skiboot] [PATCH V6 2/3] powercap: occ: Add a generic powercap framework
Shilpasri G Bhat
shilpa.bhat at linux.vnet.ibm.com
Wed Jul 19 08:01:31 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.
Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
core/Makefile.inc | 2 +-
core/powercap.c | 40 +++++++++++++++++++
hw/occ.c | 113 +++++++++++++++++++++++++++++++++++++++++++++++++++++
include/opal-api.h | 4 +-
include/powercap.h | 35 +++++++++++++++++
5 files changed, 192 insertions(+), 2 deletions(-)
create mode 100644 core/powercap.c
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..adf50c5
--- /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(token, pcap);
+
+ return OPAL_UNSUPPORTED;
+};
+
+opal_call(OPAL_SET_POWERCAP, opal_set_powercap, 3);
diff --git a/hw/occ.c b/hw/occ.c
index 01adab1..24ead8e 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 */
@@ -1192,6 +1193,8 @@ exit:
unlock(&chip->queue_lock);
}
+static void occ_add_powercap_sensors(void);
+
static void occ_cmd_interface_init(void)
{
struct occ_dynamic_data *data;
@@ -1225,8 +1228,118 @@ static void occ_cmd_interface_init(void)
&chips[i]);
i++;
}
+ occ_add_powercap_sensors();
+}
+
+/* Powercap interface */
+enum sensor_powercap_occ_attr {
+ POWERCAP_OCC_MIN,
+ POWERCAP_OCC_MAX,
+ POWERCAP_OCC_CUR,
+};
+
+static void occ_add_powercap_sensors(void)
+{
+ struct dt_node *node, *power_mgt;
+ u32 handle;
+
+ 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;
+ }
+
+ node = dt_new(power_mgt, "powercap");
+ if (!node) {
+ prerror("OCC: Failed to create powercap sensor node\n");
+ return;
+ }
+
+ handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_CUR);
+ dt_add_property_cells(node, "cap", handle);
+
+ handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_MIN);
+ dt_add_property_cells(node, "cap-min", handle);
+
+ handle = powercap_make_handle(POWERCAP_CLASS_OCC, POWERCAP_OCC_MAX);
+ dt_add_property_cells(node, "cap-max", handle);
+}
+
+int occ_get_powercap(u32 handle, u32 *pcap)
+{
+ struct occ_pstate_table *pdata;
+ struct occ_dynamic_data *ddata;
+ struct proc_chip *chip;
+ u8 attr = powercap_get_attr(handle);
+
+ chip = next_chip(NULL);
+ pdata = get_occ_pstate_table(chip);
+ if (!pdata->valid)
+ return OPAL_BUSY;
+
+ if (pdata->version != 0x90)
+ return OPAL_UNSUPPORTED;
+
+ ddata = get_occ_dynamic_data(chip);
+ switch (attr) {
+ 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(int token, u32 pcap)
+{
+ struct occ_pstate_table *pdata;
+ struct occ_dynamic_data *ddata;
+ struct proc_chip *chip;
+ int i;
+
+ chip = next_chip(NULL);
+ pdata = get_occ_pstate_table(chip);
+ if (!pdata->valid)
+ return OPAL_WRONG_STATE;
+
+ if (pdata->version != 0x90)
+ return OPAL_UNSUPPORTED;
+
+ for (i = 0; i < nr_occs; i++)
+ if (chips[i].occ_role == OCC_ROLE_MASTER)
+ break;
+
+ if (!(PPC_BIT16(*chips[i].occ_state) &
+ occ_cmds[pcap_data.cmd].state_mask))
+ return OPAL_WRONG_STATE;
+
+ 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..7bc43c5
--- /dev/null
+++ b/include/powercap.h
@@ -0,0 +1,35 @@
+/* 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,
+};
+
+#define powercap_make_handle(class, attr) ((class << 24) | attr)
+
+#define powercap_get_class(handle) ((handle >> 24) & 0xF)
+#define powercap_get_attr(handle) (handle & 0xF)
+
+/* Powercap OCC helpers */
+extern int occ_get_powercap(u32 handle, u32 *pcap);
+extern int occ_set_powercap(int token, u32 pcap);
+
+#endif /* __POWERCAP_H */
--
1.8.3.1
More information about the Skiboot
mailing list