From 606b7430077c15695a5b3bcfbad4975f00c9bf95 Mon Sep 17 00:00:00 2001 From: Wing Li Date: Wed, 14 Sep 2022 13:18:17 -0700 Subject: feat(psci): add support for OS-initiated mode This patch adds a `psci_validate_state_coordination` function that is called by `psci_cpu_suspend_start` in OS-initiated mode. This function validates the request per sections 4.2.3.2, 5.4.5, and 6.3 of the PSCI spec (DEN0022D.b): - The requested power states are consistent with the system's state - The calling core is the last running core at the requested power level This function differs from `psci_do_state_coordination` in that: - The `psci_req_local_pwr_states` map is not modified if the request were to be denied - The `state_info` argument is never modified since it contains the power states requested by the calling OS This is conditionally compiled into the build depending on the value of the `PSCI_OS_INIT_MODE` build option. Change-Id: I667041c842d2856e9d128c98db4d5ae4e4552df3 Signed-off-by: Wing Li --- lib/psci/psci_main.c | 46 ++++++++++++++++++++++++++++++++++++---------- 1 file changed, 36 insertions(+), 10 deletions(-) (limited to 'lib/psci/psci_main.c') diff --git a/lib/psci/psci_main.c b/lib/psci/psci_main.c index 4b5fc81d7..fe12f06ba 100644 --- a/lib/psci/psci_main.c +++ b/lib/psci/psci_main.c @@ -60,6 +60,10 @@ int psci_cpu_suspend(unsigned int power_state, entry_point_info_t ep; psci_power_state_t state_info = { {PSCI_LOCAL_STATE_RUN} }; plat_local_state_t cpu_pd_state; +#if PSCI_OS_INIT_MODE + unsigned int cpu_idx = plat_my_core_pos(); + plat_local_state_t prev[PLAT_MAX_PWR_LVL]; +#endif /* Validate the power_state parameter */ rc = psci_validate_power_state(power_state, &state_info); @@ -95,6 +99,18 @@ int psci_cpu_suspend(unsigned int power_state, 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 @@ -110,6 +126,16 @@ int psci_cpu_suspend(unsigned int power_state, /* 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, @@ -142,12 +168,12 @@ int psci_cpu_suspend(unsigned int power_state, * might return if the power down was abandoned for any reason, e.g. * arrival of an interrupt */ - psci_cpu_suspend_start(&ep, - target_pwrlvl, - &state_info, - is_power_down_state); + rc = psci_cpu_suspend_start(&ep, + target_pwrlvl, + &state_info, + is_power_down_state); - return PSCI_E_SUCCESS; + return rc; } @@ -187,12 +213,12 @@ int psci_system_suspend(uintptr_t entrypoint, u_register_t context_id) * might return if the power down was abandoned for any reason, e.g. * arrival of an interrupt */ - psci_cpu_suspend_start(&ep, - PLAT_MAX_PWR_LVL, - &state_info, - PSTATE_TYPE_POWERDOWN); + rc = psci_cpu_suspend_start(&ep, + PLAT_MAX_PWR_LVL, + &state_info, + PSTATE_TYPE_POWERDOWN); - return PSCI_E_SUCCESS; + return rc; } int psci_cpu_off(void) -- cgit v1.2.3