[PATCH 15/20] cpuidle/powernv: Add support for POWER ISA v3 idle states

Ram Pai linuxram at us.ibm.com
Tue Nov 29 18:35:23 AEDT 2016


Sorry. please ignore this email.
RP

On Mon, Nov 28, 2016 at 11:08:59PM -0800, linuxram at us.ibm.com wrote:
> From: Shreyas B. Prabhu <shreyas at linux.vnet.ibm.com>
> 
> POWER ISA v3 defines a new idle processor core mechanism. In summary,
>  a) new instruction named stop is added.
>  b) new per thread SPR named PSSCR is added which controls the behavior
> 	of stop instruction.
> 
> Supported idle states and value to be written to PSSCR register to enter
> any idle state is exposed via ibm,cpu-idle-state-names and
> ibm,cpu-idle-state-psscr respectively. To enter an idle state,
> platform provided power_stop() needs to be invoked with the appropriate
> PSSCR value.
> 
> This patch adds support for this new mechanism in cpuidle powernv driver.
> 
> Cc: Rafael J. Wysocki <rafael.j.wysocki at intel.com>
> Cc: Daniel Lezcano <daniel.lezcano at linaro.org>
> Cc: Rob Herring <robh+dt at kernel.org>
> Cc: Lorenzo Pieralisi <Lorenzo.Pieralisi at arm.com>
> Cc: linux-pm at vger.kernel.org
> Cc: Michael Ellerman <mpe at ellerman.id.au>
> Cc: Paul Mackerras <paulus at ozlabs.org>
> Cc: linuxppc-dev at lists.ozlabs.org
> Reviewed-by: Gautham R. Shenoy <ego at linux.vnet.ibm.com>
> Signed-off-by: Shreyas B. Prabhu <shreyas at linux.vnet.ibm.com>
> Signed-off-by: Michael Ellerman <mpe at ellerman.id.au>
> Signed-off-by: Ram Pai <linuxram at us.ibm.com>
> (cherry-picked from 3005c597ba46480b42e1fea3512c408f1830b816)
> ---
>  drivers/cpuidle/cpuidle-powernv.c |   61 +++++++++++++++++++++++++++++++++++++
>  1 files changed, 61 insertions(+), 0 deletions(-)
> 
> diff --git a/drivers/cpuidle/cpuidle-powernv.c b/drivers/cpuidle/cpuidle-powernv.c
> index bdf8dae..cab1b4b 100644
> --- a/drivers/cpuidle/cpuidle-powernv.c
> +++ b/drivers/cpuidle/cpuidle-powernv.c
> @@ -20,6 +20,8 @@
>  #include <asm/opal.h>
>  #include <asm/runlatch.h>
> 
> +#define POWERNV_THRESHOLD_LATENCY_NS 200000
> +
>  struct cpuidle_driver powernv_idle_driver = {
>  	.name             = "powernv_idle",
>  	.owner            = THIS_MODULE,
> @@ -27,6 +29,9 @@ struct cpuidle_driver powernv_idle_driver = {
> 
>  static int max_idle_state;
>  static struct cpuidle_state *cpuidle_state_table;
> +
> +static u64 stop_psscr_table[CPUIDLE_STATE_MAX];
> +
>  static u64 snooze_timeout;
>  static bool snooze_timeout_en;
> 
> @@ -91,6 +96,17 @@ static int fastsleep_loop(struct cpuidle_device *dev,
>  	return index;
>  }
>  #endif
> +
> +static int stop_loop(struct cpuidle_device *dev,
> +		     struct cpuidle_driver *drv,
> +		     int index)
> +{
> +	ppc64_runlatch_off();
> +	power9_idle_stop(stop_psscr_table[index]);
> +	ppc64_runlatch_on();
> +	return index;
> +}
> +
>  /*
>   * States for dedicated partition case.
>   */
> @@ -170,6 +186,8 @@ static int powernv_add_idle_states(void)
>  	u32 latency_ns[CPUIDLE_STATE_MAX];
>  	u32 residency_ns[CPUIDLE_STATE_MAX];
>  	u32 flags[CPUIDLE_STATE_MAX];
> +	u64 psscr_val[CPUIDLE_STATE_MAX];
> +	const char *names[CPUIDLE_STATE_MAX];
>  	int i, rc;
> 
>  	/* Currently we have snooze statically defined */
> @@ -208,12 +226,35 @@ static int powernv_add_idle_states(void)
>  		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-latencies-ns in DT\n");
>  		goto out;
>  	}
> +	if (of_property_read_string_array(power_mgt,
> +		"ibm,cpu-idle-state-names", names, dt_idle_states) < 0) {
> +		pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-names in DT\n");
> +		goto out;
> +	}
> +
> +	/*
> +	 * If the idle states use stop instruction, probe for psscr values
> +	 * which are necessary to specify required stop level.
> +	 */
> +	if (flags[0] & (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP))
> +		if (of_property_read_u64_array(power_mgt,
> +		    "ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) {
> +			pr_warn("cpuidle-powernv: missing ibm,cpu-idle-states-psscr in DT\n");
> +			goto out;
> +		}
> 
>  	rc = of_property_read_u32_array(power_mgt,
>  		"ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
> 
> 
>  	for (i = 0; i < dt_idle_states; i++) {
> +		/*
> +		 * If an idle state has exit latency beyond
> +		 * POWERNV_THRESHOLD_LATENCY_NS then don't use it
> +		 * in cpu-idle.
> +		 */
> +		if (latency_ns[i] > POWERNV_THRESHOLD_LATENCY_NS)
> +			continue;
> 
>  		/*
>  		 * Cpuidle accepts exit_latency and target_residency in us.
> @@ -226,6 +267,16 @@ static int powernv_add_idle_states(void)
>  			powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIME_VALID;
>  			powernv_states[nr_idle_states].target_residency = 100;
>  			powernv_states[nr_idle_states].enter = nap_loop;
> +		} else if ((flags[i] & OPAL_PM_STOP_INST_FAST) &&
> +				!(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
> +			strncpy(powernv_states[nr_idle_states].name,
> +				names[i], CPUIDLE_NAME_LEN);
> +			strncpy(powernv_states[nr_idle_states].desc,
> +				names[i], CPUIDLE_NAME_LEN);
> +			powernv_states[nr_idle_states].flags = 0;
> +
> +			powernv_states[nr_idle_states].enter = stop_loop;
> +			stop_psscr_table[nr_idle_states] = psscr_val[i];
>  		}
> 
>  		/*
> @@ -242,6 +293,16 @@ static int powernv_add_idle_states(void)
>  				CPUIDLE_FLAG_TIME_VALID | CPUIDLE_FLAG_TIMER_STOP;
>  			powernv_states[nr_idle_states].target_residency = 300000;
>  			powernv_states[nr_idle_states].enter = fastsleep_loop;
> +		} else if ((flags[i] & OPAL_PM_STOP_INST_DEEP) &&
> +				(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
> +			strncpy(powernv_states[nr_idle_states].name,
> +				names[i], CPUIDLE_NAME_LEN);
> +			strncpy(powernv_states[nr_idle_states].desc,
> +				names[i], CPUIDLE_NAME_LEN);
> +
> +			powernv_states[nr_idle_states].flags = CPUIDLE_FLAG_TIMER_STOP;
> +			powernv_states[nr_idle_states].enter = stop_loop;
> +			stop_psscr_table[nr_idle_states] = psscr_val[i];
>  		}
>  #endif
>  		powernv_states[nr_idle_states].exit_latency =
> -- 
> 1.7.1

-- 
Ram Pai



More information about the Linuxppc-dev mailing list