[Skiboot] [PATCH v2 5/5] occ : Add OPAL API opal_get_dynamic_update() to support runtime update

Shilpasri G Bhat shilpa.bhat at linux.vnet.ibm.com
Fri Apr 1 00:34:57 AEDT 2016


This patch adds a generic opal call to retrieve runtime 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 retrieval of frequency throttle stats later in the future.

Signed-off-by: Shilpasri G Bhat <shilpa.bhat at linux.vnet.ibm.com>
---
Changes from v1:
- Rebased on top of core/fdt changes proposed by Gavin Shan, where
  sub-device-tree-blob is created based on the phandle.
- Adding a wrapper get_node_dtb() to call __create_dtb() with inc=true
  __create_dtb(buff, len, node, true); which will flatten all the
  child nodes and properties of the device tree node

 core/fdt.c         |  13 ++++++
 core/opal.c        |  22 ++++++++++
 hw/occ.c           | 115 +++++++++++++++++++++++++++++++++++++++++++----------
 include/device.h   |   6 +++
 include/opal-api.h |  10 ++++-
 5 files changed, 144 insertions(+), 22 deletions(-)

diff --git a/core/fdt.c b/core/fdt.c
index a8b0108..35f7519 100644
--- a/core/fdt.c
+++ b/core/fdt.c
@@ -224,6 +224,19 @@ static int64_t opal_get_device_tree(uint32_t phandle,
 }
 opal_call(OPAL_GET_DEVICE_TREE, opal_get_device_tree, 3);
 
+int get_node_dtb(struct dt_node *node, void *buff, uint64_t len)
+{
+	int ret;
+
+	ret = __create_dtb(buff, len, node, true);
+	if (ret == -FDT_ERR_NOSPACE)
+		return OPAL_NO_MEM;
+	else if (ret)
+		return OPAL_EMPTY;
+
+	return OPAL_SUCCESS;
+}
+
 void *create_dtb(const struct dt_node *root)
 {
 	void *fdt = NULL;
diff --git a/core/opal.c b/core/opal.c
index b6411f0..8fefb09 100644
--- a/core/opal.c
+++ b/core/opal.c
@@ -403,3 +403,25 @@ static int64_t opal_sync_host_reboot(void)
 		return OPAL_BUSY_EVENT;
 }
 opal_call(OPAL_SYNC_HOST_REBOOT, opal_sync_host_reboot, 0);
+
+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;
+	}
+
+	if (!buffer || !len)
+		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 3762726..a7f0efb 100644
--- a/hw/occ.c
+++ b/hw/occ.c
@@ -140,9 +140,40 @@ 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;
+}
+
+#define check_and_del_property(node, str)		\
+{							\
+	struct dt_property *prop;			\
+							\
+	prop = __dt_find_property(node, str);		\
+	if (prop)					\
+		dt_del_property(power_mgt, prop);	\
+}
+
+#define dt_add_array(node, str, array, size)		\
+{							\
+	check_and_del_property(node, str);		\
+	dt_add_property(node, str, array, size);	\
+}
+
+#define dt_add_value(node, str, value)			\
+{							\
+	check_and_del_property(node, str);		\
+	dt_add_property_cells(node, str, value);	\
+}
+
 /* 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(void)
 {
 	struct proc_chip *chip;
 	uint64_t occ_data_area;
@@ -249,29 +280,26 @@ static bool add_cpu_pstate_properties(s8 *pstate_nom)
 	}
 
 	/* Add the device-tree entries */
-	dt_add_property(power_mgt, "ibm,pstate-ids", dt_id,
-			nr_pstates * sizeof(u32));
-	dt_add_property(power_mgt, "ibm,pstate-frequencies-mhz", dt_freq,
-			nr_pstates * sizeof(u32));
-	dt_add_property_cells(power_mgt, "ibm,pstate-min", occ_data->pstate_min);
-	dt_add_property_cells(power_mgt, "ibm,pstate-nominal", occ_data->pstate_nom);
-	dt_add_property_cells(power_mgt, "ibm,pstate-max", pmax);
+	dt_add_array(power_mgt, "ibm,pstate-ids", dt_id,
+		     nr_pstates * sizeof(u32));
+	dt_add_array(power_mgt, "ibm,pstate-frequencies-mhz", dt_freq,
+		     nr_pstates * sizeof(u32));
+	dt_add_value(power_mgt, "ibm,pstate-min", occ_data->pstate_min);
+	dt_add_value(power_mgt, "ibm,pstate-nominal", occ_data->pstate_nom);
+	dt_add_value(power_mgt, "ibm,pstate-max", pmax);
 
 	if (ultra_turbo_en) {
-		dt_add_property_cells(power_mgt, "ibm,pstate-turbo",
-				      occ_data->pstate_turbo);
-		dt_add_property_cells(power_mgt, "ibm,pstate-ultra-turbo",
-				      occ_data->pstate_ultra_turbo);
-		dt_add_property(power_mgt, "ibm,pstate-core-max", dt_core_max,
-				nr_cores);
+		dt_add_value(power_mgt, "ibm,pstate-turbo",
+			     occ_data->pstate_turbo);
+		dt_add_value(power_mgt, "ibm,pstate-ultra-turbo",
+			     occ_data->pstate_ultra_turbo);
+		dt_add_array(power_mgt, "ibm,pstate-core-max", dt_core_max,
+			     nr_cores);
 		free(dt_core_max);
 	}
 
-	/* Return pstate to set for each core */
-	*pstate_nom = occ_data->pstate_nom;
-
-	dt_add_property_cells(power_mgt, "#address-cells", 2);
-	dt_add_property_cells(power_mgt, "#size-cells", 0);
+	dt_add_value(power_mgt, "#address-cells", 2);
+	dt_add_value(power_mgt, "#size-cells", 0);
 	for_each_chip(chip) {
 		struct dt_node *occ_node;
 
@@ -492,12 +520,15 @@ void occ_pstates_init(void)
 	 * Check boundary conditions and add device tree nodes
 	 * and return nominal pstate to set for the core
 	 */
-	if (!add_cpu_pstate_properties(&pstate_nom)) {
+	if (!add_cpu_pstate_properties()) {
 		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) {
@@ -933,4 +964,46 @@ 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 *power_mgt, *node;
+	struct proc_chip *chip;
+	struct occ_pstate_table *occ_data;
+	int ret;
+
+	if (len > DEVICE_TREE_MAX_SIZE) {
+		prerror("OCC: Buffer length %lld is greater than %d bytes\n",
+			len, DEVICE_TREE_MAX_SIZE);
+		return OPAL_PARAMETER;
+	}
+
+	power_mgt = dt_find_by_path(dt_root, "/ibm,opal/power-mgt");
+	if (!power_mgt) {
+		prerror("OCC: /ibm,opal/power-mgt node not found\n");
+		return OPAL_CLOSED;
+	}
+
+	for_each_chip(chip) {
+		occ_data = chip_occ_data(chip);
+		if (occ_data->valid != 1) {
+			prerror("OCC: Chip %x Pstate table is not valid\n",
+				chip->id);
+			return OPAL_CLOSED;
+		}
+	}
+
+	dt_for_each_child(power_mgt, node)
+		if (strncmp(node->name, "occ", strlen("occ")) == 0)
+			dt_free(node);
 
+	if (!add_cpu_pstate_properties()) {
+		prerror("OCC: Failed to add pstate properties\n");
+		return OPAL_CLOSED;
+	}
+
+	ret = get_node_dtb(power_mgt, buff, len);
+	if (ret)
+		prerror("OCC: Failed to get the DTB for power-mgt %d\n", ret);
+
+	return ret;
+}
diff --git a/include/device.h b/include/device.h
index 28dbd5d..9eb89df 100644
--- a/include/device.h
+++ b/include/device.h
@@ -242,4 +242,10 @@ u64 dt_translate_address(const struct dt_node *node, unsigned int index,
  */
 int dt_cmp_subnodes(const struct dt_node *a,  const struct dt_node *b);
 
+/*
+ * Creates a DTB for the given device tree node and its children
+ */
+
+int get_node_dtb(struct dt_node *node, void *buff, uint64_t len);
+
 #endif /* __DEVICE_H */
diff --git a/include/opal-api.h b/include/opal-api.h
index 41af0e5..9e67271 100644
--- a/include/opal-api.h
+++ b/include/opal-api.h
@@ -164,7 +164,8 @@
 #define OPAL_CEC_REBOOT2			116
 #define OPAL_CONSOLE_FLUSH			117
 #define OPAL_GET_DEVICE_TREE			118
-#define OPAL_LAST				118
+#define OPAL_GET_DYNAMIC_UPDATE			119
+#define OPAL_LAST				119
 
 /* Device tree flags */
 
@@ -982,6 +983,13 @@ enum {
 	OPAL_REBOOT_PLATFORM_ERROR,
 };
 
+enum opal_update_type {
+	OPAL_UPDATE_TYPE_PSTATES,
+	OPAL_UPDATE_TYPE_MAX
+};
+
+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