fix(psci): do not modify higher levels for standby in OSI mode
The OSI mode for the CPU standby fast path updates the requested power
states incorrectly. psci_update_req_local_pwr_states() will not bother
saving level 0. It will also clamp the level it accesses to the
end_pwrlvl argument. Well, in the fast path, this argument is always 0
(as a condition of entering the fast path). The result is that it reads
the level 0 power state (retention) and writes it to the level 1 power
state, even though by definition, the fast path will not update higher
power levels.
The fix is to pass PLAT_MAX_PWR_LVL instead of target_pwrlvl to
psci_update_req_local_pwr_states(). However, doing that makes it
apparent that this call will not change anything and therefore there is
nothing to save - the level 0 power state is written by
psci_set_cpu_local_state(). So the save + restore are redundant. Remove
them to save on a bunch of work.
Another thing that is not considered is locking. No locks are held in
the fast path, so these updates are not safe.
Change-Id: Icc785df87b294b938b59705116369abd80ccf4da
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c
index dfec9a1..00b0003 100644
--- a/lib/psci/psci_main.c
+++ b/lib/psci/psci_main.c
@@ -64,9 +64,6 @@
psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} };
plat_local_state_t cpu_pd_state;
unsigned int cpu_idx = plat_my_core_pos();
-#if PSCI_OS_INIT_MODE
- plat_local_state_t prev[PLAT_MAX_PWR_LVL];
-#endif
#if ERRATA_SME_POWER_DOWN
/*
@@ -103,7 +100,7 @@
panic();
}
- /* Fast path for CPU standby.*/
+ /* Fast path for local CPU standby, won't interact with higher power levels. */
if (is_cpu_standby_req(is_power_down_state, target_pwrlvl)) {
if (psci_plat_pm_ops->cpu_standby == NULL) {
return PSCI_E_INVALID_PARAMS;
@@ -116,18 +113,6 @@
cpu_pd_state = state_info.pwr_domain_state[PSCI_CPU_PWR_LVL];
psci_set_cpu_local_state(cpu_pd_state);
-#if PSCI_OS_INIT_MODE
- /*
- * If in OS-initiated mode, save a copy of the previous
- * requested local power states and update the new requested
- * local power states for this CPU.
- */
- if (psci_suspend_mode == OS_INIT) {
- psci_update_req_local_pwr_states(target_pwrlvl, cpu_idx,
- &state_info, prev);
- }
-#endif
-
#if ENABLE_PSCI_STAT
plat_psci_stat_accounting_start(&state_info);
#endif
@@ -143,16 +128,6 @@
/* Upon exit from standby, set the state back to RUN. */
psci_set_cpu_local_state(PSCI_LOCAL_STATE_RUN);
-#if PSCI_OS_INIT_MODE
- /*
- * If in OS-initiated mode, restore the previous requested
- * local power states for this CPU.
- */
- if (psci_suspend_mode == OS_INIT) {
- psci_restore_req_local_pwr_states(cpu_idx, prev);
- }
-#endif
-
#if ENABLE_RUNTIME_INSTRUMENTATION
PMF_CAPTURE_TIMESTAMP(rt_instr_svc,
RT_INSTR_EXIT_HW_LOW_PWR,