Commit f3b3f284 authored by Gautham R. Shenoy's avatar Gautham R. Shenoy Committed by Michael Ellerman

powerpc/powernv/idle: Don't override default/deepest directly in kernel

Currently during idle-init on power9, if we don't find suitable stop
states in the device tree that can be used as the
default_stop/deepest_stop, we set stop0 (ESL=1,EC=1) as the default
stop state psscr to be used by power9_idle and deepest stop state
which is used by CPU-Hotplug.

However, if the platform firmware has not configured or enabled a stop
state, the kernel should not make any assumptions and fallback to a
default choice.

If the kernel uses a stop state that is not configured by the platform
firmware, it may lead to further failures which should be avoided.

In this patch, we modify the init code to ensure that the kernel uses
only the stop states exposed by the firmware through the device
tree. When a suitable default stop state isn't found, we disable
ppc_md.power_save for power9. Similarly, when a suitable
deepest_stop_state is not found in the device tree exported by the
firmware, fall back to the default busy-wait loop in the CPU-Hotplug
code.

[Changelog written with inputs from svaidy@linux.vnet.ibm.com]
Reviewed-by: default avatarNicholas Piggin <npiggin@gmail.com>
Signed-off-by: default avatarGautham R. Shenoy <ego@linux.vnet.ibm.com>
Signed-off-by: default avatarMichael Ellerman <mpe@ellerman.id.au>
parent 90061231
...@@ -147,7 +147,6 @@ u32 pnv_get_supported_cpuidle_states(void) ...@@ -147,7 +147,6 @@ u32 pnv_get_supported_cpuidle_states(void)
} }
EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states); EXPORT_SYMBOL_GPL(pnv_get_supported_cpuidle_states);
static void pnv_fastsleep_workaround_apply(void *info) static void pnv_fastsleep_workaround_apply(void *info)
{ {
...@@ -241,8 +240,9 @@ static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600, ...@@ -241,8 +240,9 @@ static DEVICE_ATTR(fastsleep_workaround_applyonce, 0600,
* The default stop state that will be used by ppc_md.power_save * The default stop state that will be used by ppc_md.power_save
* function on platforms that support stop instruction. * function on platforms that support stop instruction.
*/ */
u64 pnv_default_stop_val; static u64 pnv_default_stop_val;
u64 pnv_default_stop_mask; static u64 pnv_default_stop_mask;
static bool default_stop_found;
/* /*
* Used for ppc_md.power_save which needs a function with no parameters * Used for ppc_md.power_save which needs a function with no parameters
...@@ -262,8 +262,9 @@ u64 pnv_first_deep_stop_state = MAX_STOP_STATE; ...@@ -262,8 +262,9 @@ u64 pnv_first_deep_stop_state = MAX_STOP_STATE;
* psscr value and mask of the deepest stop idle state. * psscr value and mask of the deepest stop idle state.
* Used when a cpu is offlined. * Used when a cpu is offlined.
*/ */
u64 pnv_deepest_stop_psscr_val; static u64 pnv_deepest_stop_psscr_val;
u64 pnv_deepest_stop_psscr_mask; static u64 pnv_deepest_stop_psscr_mask;
static bool deepest_stop_found;
/* /*
* pnv_cpu_offline: A function that puts the CPU into the deepest * pnv_cpu_offline: A function that puts the CPU into the deepest
...@@ -275,7 +276,7 @@ unsigned long pnv_cpu_offline(unsigned int cpu) ...@@ -275,7 +276,7 @@ unsigned long pnv_cpu_offline(unsigned int cpu)
u32 idle_states = pnv_get_supported_cpuidle_states(); u32 idle_states = pnv_get_supported_cpuidle_states();
if (cpu_has_feature(CPU_FTR_ARCH_300)) { if (cpu_has_feature(CPU_FTR_ARCH_300) && deepest_stop_found) {
srr1 = power9_idle_stop(pnv_deepest_stop_psscr_val, srr1 = power9_idle_stop(pnv_deepest_stop_psscr_val,
pnv_deepest_stop_psscr_mask); pnv_deepest_stop_psscr_mask);
} else if (idle_states & OPAL_PM_WINKLE_ENABLED) { } else if (idle_states & OPAL_PM_WINKLE_ENABLED) {
...@@ -385,7 +386,6 @@ static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags, ...@@ -385,7 +386,6 @@ static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags,
u32 *residency_ns = NULL; u32 *residency_ns = NULL;
u64 max_residency_ns = 0; u64 max_residency_ns = 0;
int rc = 0, i; int rc = 0, i;
bool default_stop_found = false, deepest_stop_found = false;
psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val), GFP_KERNEL); psscr_val = kcalloc(dt_idle_states, sizeof(*psscr_val), GFP_KERNEL);
psscr_mask = kcalloc(dt_idle_states, sizeof(*psscr_mask), GFP_KERNEL); psscr_mask = kcalloc(dt_idle_states, sizeof(*psscr_mask), GFP_KERNEL);
...@@ -465,21 +465,24 @@ static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags, ...@@ -465,21 +465,24 @@ static int __init pnv_power9_idle_init(struct device_node *np, u32 *flags,
} }
} }
if (!default_stop_found) { if (unlikely(!default_stop_found)) {
pnv_default_stop_val = PSSCR_HV_DEFAULT_VAL; pr_warn("cpuidle-powernv: No suitable default stop state found. Disabling platform idle.\n");
pnv_default_stop_mask = PSSCR_HV_DEFAULT_MASK; } else {
pr_warn("Setting default stop psscr val=0x%016llx,mask=0x%016llx\n", ppc_md.power_save = power9_idle;
pr_info("cpuidle-powernv: Default stop: psscr = 0x%016llx,mask=0x%016llx\n",
pnv_default_stop_val, pnv_default_stop_mask); pnv_default_stop_val, pnv_default_stop_mask);
} }
if (!deepest_stop_found) { if (unlikely(!deepest_stop_found)) {
pnv_deepest_stop_psscr_val = PSSCR_HV_DEFAULT_VAL; pr_warn("cpuidle-powernv: No suitable stop state for CPU-Hotplug. Offlined CPUs will busy wait");
pnv_deepest_stop_psscr_mask = PSSCR_HV_DEFAULT_MASK; } else {
pr_warn("Setting default stop psscr val=0x%016llx,mask=0x%016llx\n", pr_info("cpuidle-powernv: Deepest stop: psscr = 0x%016llx,mask=0x%016llx\n",
pnv_deepest_stop_psscr_val, pnv_deepest_stop_psscr_val,
pnv_deepest_stop_psscr_mask); pnv_deepest_stop_psscr_mask);
} }
pr_info("cpuidle-powernv: Requested Level (RL) value of first deep stop = 0x%llx\n",
pnv_first_deep_stop_state);
out: out:
kfree(psscr_val); kfree(psscr_val);
kfree(psscr_mask); kfree(psscr_mask);
...@@ -559,8 +562,6 @@ static int __init pnv_init_idle_states(void) ...@@ -559,8 +562,6 @@ static int __init pnv_init_idle_states(void)
if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED) if (supported_cpuidle_states & OPAL_PM_NAP_ENABLED)
ppc_md.power_save = power7_idle; ppc_md.power_save = power7_idle;
else if (supported_cpuidle_states & OPAL_PM_STOP_INST_FAST)
ppc_md.power_save = power9_idle;
out: out:
return 0; return 0;
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment