|
@@ -19,6 +19,7 @@
|
|
#include <asm/firmware.h>
|
|
#include <asm/firmware.h>
|
|
#include <asm/opal.h>
|
|
#include <asm/opal.h>
|
|
#include <asm/runlatch.h>
|
|
#include <asm/runlatch.h>
|
|
|
|
+#include <asm/cpuidle.h>
|
|
|
|
|
|
/*
|
|
/*
|
|
* Expose only those Hardware idle states via the cpuidle framework
|
|
* Expose only those Hardware idle states via the cpuidle framework
|
|
@@ -34,7 +35,12 @@ static struct cpuidle_driver powernv_idle_driver = {
|
|
static int max_idle_state;
|
|
static int max_idle_state;
|
|
static struct cpuidle_state *cpuidle_state_table;
|
|
static struct cpuidle_state *cpuidle_state_table;
|
|
|
|
|
|
-static u64 stop_psscr_table[CPUIDLE_STATE_MAX];
|
|
|
|
|
|
+struct stop_psscr_table {
|
|
|
|
+ u64 val;
|
|
|
|
+ u64 mask;
|
|
|
|
+};
|
|
|
|
+
|
|
|
|
+static struct stop_psscr_table stop_psscr_table[CPUIDLE_STATE_MAX];
|
|
|
|
|
|
static u64 snooze_timeout;
|
|
static u64 snooze_timeout;
|
|
static bool snooze_timeout_en;
|
|
static bool snooze_timeout_en;
|
|
@@ -106,7 +112,8 @@ static int stop_loop(struct cpuidle_device *dev,
|
|
int index)
|
|
int index)
|
|
{
|
|
{
|
|
ppc64_runlatch_off();
|
|
ppc64_runlatch_off();
|
|
- power9_idle_stop(stop_psscr_table[index]);
|
|
|
|
|
|
+ power9_idle_stop(stop_psscr_table[index].val,
|
|
|
|
+ stop_psscr_table[index].mask);
|
|
ppc64_runlatch_on();
|
|
ppc64_runlatch_on();
|
|
return index;
|
|
return index;
|
|
}
|
|
}
|
|
@@ -178,7 +185,7 @@ static inline void add_powernv_state(int index, const char *name,
|
|
int),
|
|
int),
|
|
unsigned int target_residency,
|
|
unsigned int target_residency,
|
|
unsigned int exit_latency,
|
|
unsigned int exit_latency,
|
|
- u64 psscr_val)
|
|
|
|
|
|
+ u64 psscr_val, u64 psscr_mask)
|
|
{
|
|
{
|
|
strlcpy(powernv_states[index].name, name, CPUIDLE_NAME_LEN);
|
|
strlcpy(powernv_states[index].name, name, CPUIDLE_NAME_LEN);
|
|
strlcpy(powernv_states[index].desc, name, CPUIDLE_NAME_LEN);
|
|
strlcpy(powernv_states[index].desc, name, CPUIDLE_NAME_LEN);
|
|
@@ -186,7 +193,8 @@ static inline void add_powernv_state(int index, const char *name,
|
|
powernv_states[index].target_residency = target_residency;
|
|
powernv_states[index].target_residency = target_residency;
|
|
powernv_states[index].exit_latency = exit_latency;
|
|
powernv_states[index].exit_latency = exit_latency;
|
|
powernv_states[index].enter = idle_fn;
|
|
powernv_states[index].enter = idle_fn;
|
|
- stop_psscr_table[index] = psscr_val;
|
|
|
|
|
|
+ stop_psscr_table[index].val = psscr_val;
|
|
|
|
+ stop_psscr_table[index].mask = psscr_mask;
|
|
}
|
|
}
|
|
|
|
|
|
static int powernv_add_idle_states(void)
|
|
static int powernv_add_idle_states(void)
|
|
@@ -198,7 +206,9 @@ static int powernv_add_idle_states(void)
|
|
u32 residency_ns[CPUIDLE_STATE_MAX];
|
|
u32 residency_ns[CPUIDLE_STATE_MAX];
|
|
u32 flags[CPUIDLE_STATE_MAX];
|
|
u32 flags[CPUIDLE_STATE_MAX];
|
|
u64 psscr_val[CPUIDLE_STATE_MAX];
|
|
u64 psscr_val[CPUIDLE_STATE_MAX];
|
|
|
|
+ u64 psscr_mask[CPUIDLE_STATE_MAX];
|
|
const char *names[CPUIDLE_STATE_MAX];
|
|
const char *names[CPUIDLE_STATE_MAX];
|
|
|
|
+ u32 has_stop_states = 0;
|
|
int i, rc;
|
|
int i, rc;
|
|
|
|
|
|
/* Currently we have snooze statically defined */
|
|
/* Currently we have snooze statically defined */
|
|
@@ -245,15 +255,25 @@ static int powernv_add_idle_states(void)
|
|
|
|
|
|
/*
|
|
/*
|
|
* If the idle states use stop instruction, probe for psscr values
|
|
* If the idle states use stop instruction, probe for psscr values
|
|
- * which are necessary to specify required stop level.
|
|
|
|
|
|
+ * and psscr mask which are necessary to specify required stop level.
|
|
*/
|
|
*/
|
|
- if (flags[0] & (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP))
|
|
|
|
|
|
+ has_stop_states = (flags[0] &
|
|
|
|
+ (OPAL_PM_STOP_INST_FAST | OPAL_PM_STOP_INST_DEEP));
|
|
|
|
+ if (has_stop_states) {
|
|
if (of_property_read_u64_array(power_mgt,
|
|
if (of_property_read_u64_array(power_mgt,
|
|
"ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) {
|
|
"ibm,cpu-idle-state-psscr", psscr_val, dt_idle_states)) {
|
|
- pr_warn("cpuidle-powernv: missing ibm,cpu-idle-states-psscr in DT\n");
|
|
|
|
|
|
+ pr_warn("cpuidle-powernv: missing ibm,cpu-idle-state-psscr in DT\n");
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
|
|
+ if (of_property_read_u64_array(power_mgt,
|
|
|
|
+ "ibm,cpu-idle-state-psscr-mask",
|
|
|
|
+ psscr_mask, dt_idle_states)) {
|
|
|
|
+ pr_warn("cpuidle-powernv:Missing ibm,cpu-idle-state-psscr-mask in DT\n");
|
|
|
|
+ goto out;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
rc = of_property_read_u32_array(power_mgt,
|
|
rc = of_property_read_u32_array(power_mgt,
|
|
"ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
|
|
"ibm,cpu-idle-state-residency-ns", residency_ns, dt_idle_states);
|
|
|
|
|
|
@@ -276,6 +296,16 @@ static int powernv_add_idle_states(void)
|
|
else
|
|
else
|
|
target_residency = 0;
|
|
target_residency = 0;
|
|
|
|
|
|
|
|
+ if (has_stop_states) {
|
|
|
|
+ int err = validate_psscr_val_mask(&psscr_val[i],
|
|
|
|
+ &psscr_mask[i],
|
|
|
|
+ flags[i]);
|
|
|
|
+ if (err) {
|
|
|
|
+ report_invalid_psscr_val(psscr_val[i], err);
|
|
|
|
+ continue;
|
|
|
|
+ }
|
|
|
|
+ }
|
|
|
|
+
|
|
/*
|
|
/*
|
|
* For nap and fastsleep, use default target_residency
|
|
* For nap and fastsleep, use default target_residency
|
|
* values if f/w does not expose it.
|
|
* values if f/w does not expose it.
|
|
@@ -286,13 +316,13 @@ static int powernv_add_idle_states(void)
|
|
/* Add NAP state */
|
|
/* Add NAP state */
|
|
add_powernv_state(nr_idle_states, "Nap",
|
|
add_powernv_state(nr_idle_states, "Nap",
|
|
CPUIDLE_FLAG_NONE, nap_loop,
|
|
CPUIDLE_FLAG_NONE, nap_loop,
|
|
- target_residency, exit_latency, 0);
|
|
|
|
|
|
+ target_residency, exit_latency, 0, 0);
|
|
} else if ((flags[i] & OPAL_PM_STOP_INST_FAST) &&
|
|
} else if ((flags[i] & OPAL_PM_STOP_INST_FAST) &&
|
|
!(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
|
|
!(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
|
|
add_powernv_state(nr_idle_states, names[i],
|
|
add_powernv_state(nr_idle_states, names[i],
|
|
CPUIDLE_FLAG_NONE, stop_loop,
|
|
CPUIDLE_FLAG_NONE, stop_loop,
|
|
target_residency, exit_latency,
|
|
target_residency, exit_latency,
|
|
- psscr_val[i]);
|
|
|
|
|
|
+ psscr_val[i], psscr_mask[i]);
|
|
}
|
|
}
|
|
|
|
|
|
/*
|
|
/*
|
|
@@ -308,13 +338,13 @@ static int powernv_add_idle_states(void)
|
|
add_powernv_state(nr_idle_states, "FastSleep",
|
|
add_powernv_state(nr_idle_states, "FastSleep",
|
|
CPUIDLE_FLAG_TIMER_STOP,
|
|
CPUIDLE_FLAG_TIMER_STOP,
|
|
fastsleep_loop,
|
|
fastsleep_loop,
|
|
- target_residency, exit_latency, 0);
|
|
|
|
|
|
+ target_residency, exit_latency, 0, 0);
|
|
} else if ((flags[i] & OPAL_PM_STOP_INST_DEEP) &&
|
|
} else if ((flags[i] & OPAL_PM_STOP_INST_DEEP) &&
|
|
(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
|
|
(flags[i] & OPAL_PM_TIMEBASE_STOP)) {
|
|
add_powernv_state(nr_idle_states, names[i],
|
|
add_powernv_state(nr_idle_states, names[i],
|
|
CPUIDLE_FLAG_TIMER_STOP, stop_loop,
|
|
CPUIDLE_FLAG_TIMER_STOP, stop_loop,
|
|
target_residency, exit_latency,
|
|
target_residency, exit_latency,
|
|
- psscr_val[i]);
|
|
|
|
|
|
+ psscr_val[i], psscr_mask[i]);
|
|
}
|
|
}
|
|
#endif
|
|
#endif
|
|
nr_idle_states++;
|
|
nr_idle_states++;
|