[Skiboot] [RFC PATCH 2/2] occ : Add opal call to support runtime update

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Mon Feb 15 15:13:48 AEDT 2016


This patch adds a generic opal call to retrieve updated information.
One such data is pstate table. OCC can provide new frequencies
to the host which needs to be parsed and passed to linux for cpufreq
to consume it. This call can be extended to support reading sensors,
frequency throttle stats later in the future.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
 core/opal.c        | 19 ++++++++++++
 hw/occ.c           | 87 +++++++++++++++++++++++++++++++++++++++++++-----------
 include/opal-api.h | 10 ++++++-
 3 files changed, 98 insertions(+), 18 deletions(-)

diff --git a/core/opal.c b/core/opal.c
index b6411f0..70ad574 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -403,3 +403,22 @@ static int64_t opal_sync_host_reboot(void)
 		return OPAL_BUSY_EVENT;
 }
 opal_call(OPAL_SYNC_HOST_REBOOT, opal_sync_host_reboot, 0);
+
+/* Opal call to get runtime updates */
+static int opal_get_dynamic_update(enum opal_update_type type, void *buffer,
+				   uint64_t len)
+{
+	if (type > OPAL_UPDATE_TYPE_MAX) {
+		prerror("Unsupported dynamic update type %d\n", type);
+		return OPAL_PARAMETER;
+	}
+
+	switch (type) {
+	case OPAL_UPDATE_TYPE_PSTATES:
+		return opal_get_dynamic_pstate_update(buffer, len);
+	default:
+		prerror("Unsupported dynamic update type %d\n", type);
+		return OPAL_PARAMETER;
+	}
+}
+opal_call(OPAL_GET_DYNAMIC_UPDATE, opal_get_dynamic_update, 3);
diff --git a/hw/occ.c b/hw/occ.c
index 93dd7ce..301d2e4 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -27,6 +27,7 @@
 #include <opal-api.h>
 #include <opal-msg.h>
 #include <timer.h>
+#include <libfdt/libfdt.h>
 
 /* OCC Communication Area for PStates */
 
@@ -140,14 +141,23 @@ static bool wait_for_all_occ_init(void)
 	return true;
 }
 
+/* Return nominal pstate to set in each core */
+static s8 get_nominal_pstate(void)
+{
+	struct proc_chip *chip;
+	struct occ_pstate_table *occ_data;
+
+	chip = next_chip(NULL);
+	occ_data = chip_occ_data(chip);
+	return occ_data->pstate_nom;
+}
+
 /* Add device tree properties to describe pstates states */
-/* Retrun nominal pstate to set in each core */
-static bool add_cpu_pstate_properties(s8 *pstate_nom)
+static bool add_cpu_pstate_properties(struct dt_node *power_mgt)
 {
 	struct proc_chip *chip;
 	uint64_t occ_data_area;
 	struct occ_pstate_table *occ_data;
-	struct dt_node *power_mgt;
 	u8 nr_pstates, nr_cores = 0;
 	s8 pmax;
 	/* Arrays for device tree */
@@ -197,12 +207,6 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
 		return false;
 	}
 
-	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 false;
-	}
-
 	rc = false;
 
 	/* Setup arrays for device-tree */
@@ -267,9 +271,6 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
 		free(dt_core_max);
 	}
 
-	/* Return pstate to set for each core */
-	*pstate_nom = occ_data->pstate_nom;
-
 	for_each_chip(chip) {
 		struct dt_node *occ_node;
 
@@ -461,6 +462,7 @@ done:
 /* Called after OCC init on P8 */
 void occ_pstates_init(void)
 {
+	struct dt_node *power_mgt;
 	struct proc_chip *chip;
 	struct cpu_thread *c;
 	s8 pstate_nom;
@@ -484,16 +486,21 @@ void occ_pstates_init(void)
 		return;
 	}
 
-	/*
-	 * Check boundary conditions and add device tree nodes
-	 * and return nominal pstate to set for the core
-	 */
-	if (!add_cpu_pstate_properties(&pstate_nom)) {
+	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;
+	}
+
+	/* Check boundary conditions and add device tree nodes */
+	if (!add_cpu_pstate_properties(power_mgt)) {
 		log_simple_error(&e_info(OPAL_RC_OCC_PSTATE_INIT),
 			"Skiping core cpufreq init due to OCC error\n");
 		return;
 	}
 
+	/* Get nominal pstate to set for the core */
+	pstate_nom = get_nominal_pstate();
 	/* Setup host based pstates and set nominal frequency */
 	for_each_chip(chip) {
 		for_each_available_core_in_chip(c, chip->id) {
@@ -929,4 +936,50 @@ void occ_fsp_init(void)
 		fsp_register_client(&fsp_occ_client, FSP_MCLASS_OCC);
 }
 
+int opal_get_dynamic_pstate_update(void *buff, uint64_t len)
+{
+	struct dt_node *new_dt_root, *power_mgt;
+	void *fdt;
+	int ret;
+
+	if (len > DEVICE_TREE_MAX_SIZE) {
+		prerror("OCC: Invalid DT size %lld\n", len);
+		return OPAL_PARAMETER;
+	}
+
+	last_phandle = 0;
+	new_dt_root = dt_new_root("");
+	if (!new_dt_root) {
+		prerror("OCC: Cannote create new_dt_root\n");
+		return OPAL_NO_MEM;
+	}
 
+	power_mgt = dt_new(new_dt_root, "power-mgt");
+	if (!power_mgt) {
+		prerror("OCC: Cannot create dt node /power-mgt\n");
+		ret = OPAL_NO_MEM;
+		goto free_dt_root;
+	}
+
+	if (!add_cpu_pstate_properties(power_mgt)) {
+		prerror("OCC: Pstates reinitialization failed\n");
+		ret = OPAL_INTERNAL_ERROR;
+		goto free_dt_root;
+	}
+
+	fdt = create_dtb(new_dt_root);
+	if (!fdt) {
+		prerror("OCC: DTB creation failed\n");
+		ret = OPAL_INTERNAL_ERROR;
+		goto free_dt_root;
+	}
+
+	ret = fdt_open_into(fdt, buff, fdt_totalsize(fdt));
+	if (ret)
+		prerror("fdt_move failed %d\n", ret);
+
+	free(fdt);
+free_dt_root:
+	dt_free(new_dt_root);
+	return ret;
+}
diff --git a/include/opal-api.h b/include/opal-api.h
index 369aa93..2727fa6 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -163,7 +163,8 @@
 #define OPAL_LEDS_SET_INDICATOR			115
 #define OPAL_CEC_REBOOT2			116
 #define OPAL_CONSOLE_FLUSH			117
-#define OPAL_LAST				117
+#define OPAL_GET_DYNAMIC_UPDATE			118
+#define OPAL_LAST				118
 
 /* Device tree flags */
 
@@ -980,6 +981,13 @@ enum {
 	OPAL_REBOOT_PLATFORM_ERROR,
 };
 
+enum opal_update_type {
+	OPAL_UPDATE_TYPE_PSTATES,
+	OPAL_UPDATE_TYPE_MAX
+};
+
+extern int opal_get_dynamic_pstate_update(void *buff, uint64_t len);
+
 #endif /* __ASSEMBLY__ */
 
 #endif /* __OPAL_API_H */
-- 
1.9.3



More information about the Skiboot mailing list