[RFC,1/2] SLW: Add new idle device-tree format

Message ID 20180802044507.7579-2-akshay.adiga@linux.vnet.ibm.com
State New
Headers show
Series
  • New device-tree format & Opal based idle save-restore
Related show

Checks

Context Check Description
snowpatch_ozlabs/apply_patch fail Failed to apply to any branch

Commit Message

Akshay Adiga Aug. 2, 2018, 4:45 a.m.
Add stop states under ibm,idle-states in addition to the current array
based device tree properties.

Drawback of the array based dt node is that versioning of idle states is
not possible. Future kernels will have capability to handle newer stop
sates, hence versioning will help kenrnel to selectively enable states
based on its capability. The new device tree node is extensible and
has a compatible string for each idle-state.

Linux kernel can now look at the version string and decide if it has the
ability to handle that idle state. Henceforth, if kernel does not know
about a version it checks if it has "opal-supported", in which case it
will use opal-call-based-method to execute stop state. When both
"opal-supported" and  version string  are unknown, it will skip all deeper
states.

"cpuidle" and "cpuoffline" indicates that state should be used for
cpuidle or hotplug.

Final output
       power-mgt {
            ...
         ibm,enabled-stop-levels = <0xec000000>;
         ibm,cpu-idle-state-psscr-mask = <0x0 0x3003ff 0x0 0x3003ff>;
         ibm,cpu-idle-state-latencies-ns = <0x3e8 0x7d0>;
         ibm,cpu-idle-state-psscr = <0x0 0x330 0x0 0x300330>;
         ibm,cpu-idle-state-flags = <0x100000 0x101000>;
         ibm,cpu-idle-state-residency-ns = <0x2710 0x4e20>;
         ibm,idle-states {
                     stop4 {
                         flags = <0x207000>;
                         compatible = "ibm,state-v1",
                                      "cpuidle",
                                      "opal-supported";
                         psscr-mask = <0x0 0x3003ff>;
                         handle = <0x102>;
                         latency-ns = <0x186a0>;
                         residency-ns = <0x989680>;
                         psscr = <0x0 0x300374>;
                  };
                    ...
                    stop11 {
                     ...
                         compatible = "ibm,state-v1",
                                      "cpuoffline",
                                      "opal-supported";
                         ...
                  };
             };
TODO:
 - Add seperate latency/residency for OPAL call.

Signed-off-by: Akshay Adiga <akshay.adiga@linux.vnet.ibm.com>
---
 hw/slw.c | 123 ++++++++++++++++++++++++++++++++++++++++++++++---------
 1 file changed, 103 insertions(+), 20 deletions(-)

Patch

diff --git a/hw/slw.c b/hw/slw.c
index 49bcd839..b00790ef 100644
--- a/hw/slw.c
+++ b/hw/slw.c
@@ -414,8 +414,12 @@  static bool idle_prepare_core(struct proc_chip *chip, struct cpu_thread *c)
 
 /* Define device-tree fields */
 #define MAX_NAME_LEN	16
+#define MAX_VERSION_LEN	25
 struct cpu_idle_states {
 	char name[MAX_NAME_LEN];
+	char version[MAX_VERSION_LEN];
+	char type[MAX_VERSION_LEN];
+	u32 dt_node_type;
 	u32 latency_ns;
 	u32 residency_ns;
 	/*
@@ -504,6 +508,8 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 	{
 		.name = "stop0_lite", /* Enter stop0 with no state loss */
 		.latency_ns = 1000,
+		.dt_node_type = 0,
+		.version = "ibm,state-v1",
 		.residency_ns = 10000,
 		.flags = 0*OPAL_PM_DEC_STOP \
 		       | 0*OPAL_PM_TIMEBASE_STOP  \
@@ -518,6 +524,8 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 	{
 		.name = "stop0",
 		.latency_ns = 2000,
+		.dt_node_type = 0,
+		.version = "ibm,state-v1",
 		.residency_ns = 20000,
 		.flags = 0*OPAL_PM_DEC_STOP \
 		       | 0*OPAL_PM_TIMEBASE_STOP  \
@@ -536,6 +544,10 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 
 	{
 		.name = "stop1",
+		.dt_node_type = 1,
+		.version = "ibm,state-v1",
+		.type = "cpuidle",
+		.opal_supported = true,
 		.latency_ns = 5000,
 		.residency_ns = 50000,
 		.flags = 0*OPAL_PM_DEC_STOP \
@@ -557,6 +569,10 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 
 	{
 		.name = "stop2",
+		.dt_node_type = 1,
+		.version = "ibm,state-v1",
+		.type = "cpuidle",
+		.opal_supported = true,
 		.latency_ns = 10000,
 		.residency_ns = 100000,
 		.flags = 0*OPAL_PM_DEC_STOP \
@@ -573,6 +589,10 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 		.pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
 	{
 		.name = "stop4",
+		.dt_node_type = 1,
+		.version = "ibm,state-v1",
+		.type = "cpuidle",
+		.opal_supported = true,
 		.latency_ns = 100000,
 		.residency_ns = 10000000,
 		.flags = 0*OPAL_PM_DEC_STOP \
@@ -589,6 +609,10 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 		.pm_ctrl_reg_mask = OPAL_PM_PSSCR_MASK },
 	{
 		.name = "stop5",
+		.dt_node_type = 1,
+		.version = "ibm,state-v1",
+		.type = "cpuidle",
+		.opal_supported = true,
 		.latency_ns = 200000,
 		.residency_ns = 20000000,
 		.flags = 0*OPAL_PM_DEC_STOP \
@@ -606,6 +630,11 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 
 	{
 		.name = "stop8",
+		.dt_node_type = 1,
+		.version = "ibm,cpuidle-state-v1",
+		.version = "ibm,state-v1",
+		.type = "cpuoffline",
+		.opal_supported = true,
 		.latency_ns = 2000000,
 		.residency_ns = 20000000,
 		.flags = 1*OPAL_PM_DEC_STOP \
@@ -623,6 +652,10 @@  static struct cpu_idle_states power9_cpu_idle_states[] = {
 
 	{
 		.name = "stop11",
+		.dt_node_type = 1,
+		.version = "ibm,state-v1",
+		.type = "cpuoffline",
+		.opal_supported = true,
 		.latency_ns = 10000000,
 		.residency_ns = 100000000,
 		.flags = 1*OPAL_PM_DEC_STOP \
@@ -1011,34 +1044,84 @@  void add_cpu_idle_state_properties(void)
 				}
 			}
 		}
+		if ( states[i].dt_node_type == 0) {
+			prlog(PR_NOTICE, "SLW: Enabling: %s\n", states[i].name);
 
-		prlog(PR_NOTICE, "SLW: Enabling: %s\n", states[i].name);
+			/*
+			 * If a state is supported add each of its property
+			 * to its corresponding property buffer.
+			 */
+			strncpy(name_buf, states[i].name, MAX_NAME_LEN);
+			name_buf = name_buf + strlen(states[i].name) + 1;
 
-		/*
-		 * If a state is supported add each of its property
-		 * to its corresponding property buffer.
-		 */
-		strncpy(name_buf, states[i].name, MAX_NAME_LEN);
-		name_buf = name_buf + strlen(states[i].name) + 1;
+			*latency_ns_buf = cpu_to_fdt32(states[i].latency_ns);
+			latency_ns_buf++;
+
+			*residency_ns_buf = cpu_to_fdt32(states[i].residency_ns);
+			residency_ns_buf++;
 
-		*latency_ns_buf = cpu_to_fdt32(states[i].latency_ns);
-		latency_ns_buf++;
+			*flags_buf = cpu_to_fdt32(states[i].flags);
+			flags_buf++;
 
-		*residency_ns_buf = cpu_to_fdt32(states[i].residency_ns);
-		residency_ns_buf++;
+			*pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val);
+			pm_ctrl_reg_val_buf++;
 
-		*flags_buf = cpu_to_fdt32(states[i].flags);
-		flags_buf++;
+			*pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask);
+			pm_ctrl_reg_mask_buf++;
 
-		*pm_ctrl_reg_val_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val);
-		pm_ctrl_reg_val_buf++;
+			/* Increment buffer length trackers */
+			name_buf_len += strlen(states[i].name) + 1;
+			num_supported_idle_states++;
 
-		*pm_ctrl_reg_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask);
-		pm_ctrl_reg_mask_buf++;
+		} else	if ( states[i].dt_node_type == 1 ) {
 
-		/* Increment buffer length trackers */
-		name_buf_len += strlen(states[i].name) + 1;
-		num_supported_idle_states++;
+			struct dt_node *parent_node , *dt_state_node;
+			char version_buf[MAX_VERSION_LEN];
+			u32 *lat_buf, *res_buf , *flg_buf;
+			u64 *psscr_buf , *psscr_mask_buf;
+
+			lat_buf = malloc(sizeof(u32));
+			res_buf = malloc(sizeof(u32));
+			flg_buf = malloc(sizeof(u32));
+			psscr_buf = malloc(sizeof(u64));
+			psscr_mask_buf = malloc(sizeof(u64));
+			prlog(PR_NOTICE, "SLW: Enabling: %s in new format\n", states[i].name);
+
+			parent_node = dt_new_check(power_mgt,  "ibm,idle-states");
+			if (!parent_node) {
+				prlog(PR_ERR, "Error creating ibm,idle-states\n");
+			}
+			dt_state_node = dt_new_check(parent_node, states[i].name);
+			if (!dt_state_node) {
+				prlog(PR_ERR, "Error creating %s\n", states[i].name);
+			}
+			strncpy(version_buf,states[i].version, strlen(states[i].version)+1);
+			if (states[i].opal_supported) {
+				dt_add_property_strings(dt_state_node,
+							"compatible",version_buf, states[i].type,
+							"opal-supported");
+			} else {
+				dt_add_property_strings(dt_state_node,
+							"compatible",version_buf, states[i].type);
+			}
+
+			*lat_buf = cpu_to_fdt32(states[i].latency_ns);
+			dt_add_property(dt_state_node, "latency-ns",lat_buf, sizeof(u32));
+			*res_buf = cpu_to_fdt32(states[i].residency_ns);
+			dt_add_property(dt_state_node, "residency-ns",res_buf,sizeof(u32));
+			*flg_buf = cpu_to_fdt32(states[i].flags);
+			dt_add_property(dt_state_node, "flags",flg_buf,sizeof(u32));
+			*psscr_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_val);
+			dt_add_property(dt_state_node, "psscr", psscr_buf , sizeof(u64));
+			*psscr_mask_buf = cpu_to_fdt64(states[i].pm_ctrl_reg_mask);
+			dt_add_property(dt_state_node, "psscr-mask", psscr_mask_buf ,sizeof(u64));
+			free(res_buf);
+			free(lat_buf);
+			free(flg_buf);
+			free(psscr_buf);
+			free(psscr_mask_buf);
+
+		}
 
 	}