@@ -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
new file mode 100644
@@ -0,0 +1,49 @@
+/* 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 <opal.h>
+
+static inline int get_powercap_type(u32 handle)
+{
+ return ((handle >> 24) & 0xF);
+}
+
+static int opal_get_powercap(u32 handle, u32 *data)
+{
+ u8 type = get_powercap_type(handle);
+
+ if (!data || !opal_addr_valid(data))
+ return OPAL_PARAMETER;
+
+ if (type == OPAL_POWERCAP_TYPE_OCC)
+ return occ_get_powercap(handle, data);
+
+ return OPAL_UNSUPPORTED;
+};
+
+opal_call(OPAL_GET_POWERCAP, opal_get_powercap, 2);
+
+static int opal_set_powercap(u32 handle, void *data, int token)
+{
+ u8 type = get_powercap_type(handle);
+
+ if (type == OPAL_POWERCAP_TYPE_OCC)
+ return occ_set_powercap(token, data);
+
+ return OPAL_UNSUPPORTED;
+};
+
+opal_call(OPAL_SET_POWERCAP, opal_set_powercap, 3);
@@ -1244,6 +1244,111 @@ static void occ_cmd_interface_init(void)
opal_register(OPAL_OCC_COMMAND, opal_occ_command, 4);
}
+enum occ_powercap_attr {
+ OCC_POWERCAP_ATTR_MIN,
+ OCC_POWERCAP_ATTR_MAX,
+ OCC_POWERCAP_ATTR_CUR,
+ OCC_POWERCAP_ATTR_LAST
+};
+
+int occ_get_powercap(u32 handle, u32 *data)
+{
+ struct occ_pstate_table *pdata;
+ struct occ_dynamic_data *ddata;
+ struct proc_chip *chip;
+ u8 attr = handle & 0xF;
+
+ 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 OCC_POWERCAP_ATTR_MIN:
+ *data = ddata->min_pwr_cap;
+ break;
+ case OCC_POWERCAP_ATTR_MAX:
+ *data = ddata->max_pwr_cap;
+ break;
+ case OCC_POWERCAP_ATTR_CUR:
+ *data = ddata->cur_pwr_cap;
+ break;
+ default:
+ return OPAL_UNSUPPORTED;
+ }
+
+ return OPAL_SUCCESS;
+}
+
+int occ_set_powercap(int token, struct opal_occ_cmd_rsp_msg *msg)
+{
+ struct occ_pstate_table *pdata;
+ struct proc_chip *chip;
+ int i;
+
+ chip = next_chip(NULL);
+ pdata = get_occ_pstate_table(chip);
+ if (!pdata->valid)
+ return OPAL_BUSY;
+
+ if (pdata->version != 0x90)
+ return OPAL_UNSUPPORTED;
+
+ for (i = 0; i < nr_occs; i++)
+ if (chips[i].occ_role == OCC_ROLE_MASTER)
+ break;
+
+ return opal_occ_command(chips[i].id, msg, token, false);
+};
+
+static void occ_add_powercap_sensors(void)
+{
+ struct occ_pstate_table *pdata;
+ struct proc_chip *chip;
+ struct dt_node *power_mgt, *powercap;
+ int i;
+ const char *powercap_node_strings[] = {
+ "system-min-powercap",
+ "system-max-powercap",
+ "system-cur-powercap",
+ };
+
+ chip = next_chip(NULL);
+ pdata = get_occ_pstate_table(chip);
+ if (pdata->version != 0x90)
+ return;
+
+ 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;
+ }
+
+ powercap = dt_new(power_mgt, "powercap");
+ if (!powercap) {
+ prerror("OCC: Failed to create powercap node\n");
+ return;
+ }
+
+ for (i = 0; i < OCC_POWERCAP_ATTR_LAST; i++) {
+ struct dt_node *node;
+ u32 handle;
+
+ node = dt_new(powercap, powercap_node_strings[i]);
+ if (!node) {
+ prerror("OCC: Failed to create powercap sub node\n");
+ return;
+ }
+
+ handle = make_powercap_handle(OPAL_POWERCAP_TYPE_OCC, i);
+ dt_add_property_cells(node, "handle", handle);
+ }
+}
+
/* CPU-OCC PState init */
/* Called after OCC init on P8 and P9 */
void occ_pstates_init(void)
@@ -1314,6 +1419,9 @@ void occ_pstates_init(void)
/* Init OPAL-OCC command-response interface */
occ_cmd_interface_init();
+
+ /* Add powercap sensors*/
+ occ_add_powercap_sensors();
}
struct occ_load_req {
@@ -209,7 +209,9 @@
#define OPAL_IMC_COUNTERS_START 150
#define OPAL_IMC_COUNTERS_STOP 151
#define OPAL_OCC_COMMAND 152
-#define OPAL_LAST 152
+#define OPAL_SET_POWERCAP 153
+#define OPAL_GET_POWERCAP 154
+#define OPAL_LAST 154
/* Device tree flags */
@@ -1110,6 +1112,21 @@ struct opal_occ_rsp_data {
u8 data[];
};
+/* Powercap */
+
+enum opal_powercap_type {
+ OPAL_POWERCAP_TYPE_OCC,
+};
+
+static inline int make_powercap_handle(u8 type, u8 attr)
+{
+ u32 handle = ((type << 24) | attr);
+ return handle;
+}
+
+int occ_set_powercap(int token, struct opal_occ_cmd_rsp_msg *msg);
+int occ_get_powercap(u32 handle, u32 *data);
+
enum opal_prd_msg_type {
OPAL_PRD_MSG_TYPE_INIT = 0, /* HBRT --> OPAL */
OPAL_PRD_MSG_TYPE_FINI, /* HBRT/kernel --> OPAL */
This patch adds a generic powercap framework and exports OCC powercap sensors. Signed-off-by: Shilpasri G Bhat <shilpa.bhat@linux.vnet.ibm.com> --- core/Makefile.inc | 2 +- core/powercap.c | 49 ++++++++++++++++++++++++ hw/occ.c | 108 +++++++++++++++++++++++++++++++++++++++++++++++++++++ include/opal-api.h | 19 +++++++++- 4 files changed, 176 insertions(+), 2 deletions(-) create mode 100644 core/powercap.c