From f1054c93ccf892f79e340e03201d4a25c119831c Mon Sep 17 00:00:00 2001 From: Achin Gupta Date: Mon, 7 Sep 2015 20:43:27 +0100 Subject: [PATCH] Pass the target suspend level to SPD suspend hooks In certain Trusted OS implementations it is a requirement to pass them the highest power level which will enter a power down state during a PSCI CPU_SUSPEND or SYSTEM_SUSPEND API invocation. This patch passes this power level to the SPD in the "max_off_pwrlvl" parameter of the svc_suspend() hook. Currently, the highest power level which was requested to be placed in a low power state (retention or power down) is passed to the SPD svc_suspend_finish() hook. This hook is called after emerging from the low power state. It is more useful to pass the highest power level which was powered down instead. This patch does this by changing the semantics of the parameter passed to an SPD's svc_suspend_finish() hook. The name of the parameter has been changed from "suspend_level" to "max_off_pwrlvl" as well. Same changes have been made to the parameter passed to the tsp_cpu_resume_main() function. NOTE: THIS PATCH CHANGES THE SEMANTICS OF THE EXISTING "svc_suspend_finish()" API BETWEEN THE PSCI AND SPD/SP IMPLEMENTATIONS. THE LATTER MIGHT NEED UPDATES TO ENSURE CORRECT BEHAVIOUR. Change-Id: If3a9d39b13119bbb6281f508a91f78a2f46a8b90 --- bl32/tsp/tsp_main.c | 6 +++--- include/bl31/services/psci.h | 4 ++-- services/spd/opteed/opteed_pm.c | 8 ++++---- services/spd/tspd/tspd_pm.c | 8 ++++---- services/std_svc/psci/psci_suspend.c | 14 ++++++++------ 5 files changed, 21 insertions(+), 19 deletions(-) diff --git a/bl32/tsp/tsp_main.c b/bl32/tsp/tsp_main.c index b002addfb..359b9e169 100644 --- a/bl32/tsp/tsp_main.c +++ b/bl32/tsp/tsp_main.c @@ -251,7 +251,7 @@ tsp_args_t *tsp_cpu_suspend_main(uint64_t arg0, * cpu's architectural state has been restored after wakeup from an earlier psci * cpu_suspend request. ******************************************************************************/ -tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level, +tsp_args_t *tsp_cpu_resume_main(uint64_t max_off_pwrlvl, uint64_t arg1, uint64_t arg2, uint64_t arg3, @@ -272,8 +272,8 @@ tsp_args_t *tsp_cpu_resume_main(uint64_t suspend_level, #if LOG_LEVEL >= LOG_LEVEL_INFO spin_lock(&console_lock); - INFO("TSP: cpu 0x%lx resumed. suspend level %ld\n", - read_mpidr(), suspend_level); + INFO("TSP: cpu 0x%lx resumed. maximum off power level %ld\n", + read_mpidr(), max_off_pwrlvl); INFO("TSP: cpu 0x%lx: %d smcs, %d erets %d cpu suspend requests\n", read_mpidr(), tsp_stats[linear_id].smc_count, diff --git a/include/bl31/services/psci.h b/include/bl31/services/psci.h index 004dd6146..30a53ca27 100644 --- a/include/bl31/services/psci.h +++ b/include/bl31/services/psci.h @@ -286,9 +286,9 @@ typedef struct plat_psci_ops { typedef struct spd_pm_ops { void (*svc_on)(uint64_t target_cpu); int32_t (*svc_off)(uint64_t __unused); - void (*svc_suspend)(uint64_t __unused); + void (*svc_suspend)(uint64_t max_off_pwrlvl); void (*svc_on_finish)(uint64_t __unused); - void (*svc_suspend_finish)(uint64_t suspend_level); + void (*svc_suspend_finish)(uint64_t max_off_pwrlvl); int32_t (*svc_migrate)(uint64_t from_cpu, uint64_t to_cpu); int32_t (*svc_migrate_info)(uint64_t *resident_cpu); void (*svc_system_off)(void); diff --git a/services/spd/opteed/opteed_pm.c b/services/spd/opteed/opteed_pm.c index 50994d011..bd3185ce6 100644 --- a/services/spd/opteed/opteed_pm.c +++ b/services/spd/opteed/opteed_pm.c @@ -81,7 +81,7 @@ static int32_t opteed_cpu_off_handler(uint64_t unused) * This cpu is being suspended. S-EL1 state must have been saved in the * resident cpu (mpidr format) if it is a UP/UP migratable OPTEE. ******************************************************************************/ -static void opteed_cpu_suspend_handler(uint64_t unused) +static void opteed_cpu_suspend_handler(uint64_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); @@ -147,7 +147,7 @@ static void opteed_cpu_on_finish_handler(uint64_t unused) * completed the preceding suspend call. Use that context to program an entry * into OPTEE to allow it to do any remaining book keeping ******************************************************************************/ -static void opteed_cpu_suspend_finish_handler(uint64_t suspend_level) +static void opteed_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); @@ -156,10 +156,10 @@ static void opteed_cpu_suspend_finish_handler(uint64_t suspend_level) assert(optee_vectors); assert(get_optee_pstate(optee_ctx->state) == OPTEE_PSTATE_SUSPEND); - /* Program the entry point, suspend_level and enter the SP */ + /* Program the entry point, max_off_pwrlvl and enter the SP */ write_ctx_reg(get_gpregs_ctx(&optee_ctx->cpu_ctx), CTX_GPREG_X0, - suspend_level); + max_off_pwrlvl); cm_set_elr_el3(SECURE, (uint64_t) &optee_vectors->cpu_resume_entry); rc = opteed_synchronous_sp_entry(optee_ctx); diff --git a/services/spd/tspd/tspd_pm.c b/services/spd/tspd/tspd_pm.c index bc9eb7659..5089420d0 100644 --- a/services/spd/tspd/tspd_pm.c +++ b/services/spd/tspd/tspd_pm.c @@ -82,7 +82,7 @@ static int32_t tspd_cpu_off_handler(uint64_t unused) * This cpu is being suspended. S-EL1 state must have been saved in the * resident cpu (mpidr format) if it is a UP/UP migratable TSP. ******************************************************************************/ -static void tspd_cpu_suspend_handler(uint64_t unused) +static void tspd_cpu_suspend_handler(uint64_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); @@ -157,7 +157,7 @@ static void tspd_cpu_on_finish_handler(uint64_t unused) * completed the preceding suspend call. Use that context to program an entry * into the TSP to allow it to do any remaining book keeping ******************************************************************************/ -static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level) +static void tspd_cpu_suspend_finish_handler(uint64_t max_off_pwrlvl) { int32_t rc = 0; uint32_t linear_id = plat_my_core_pos(); @@ -166,10 +166,10 @@ static void tspd_cpu_suspend_finish_handler(uint64_t suspend_level) assert(tsp_vectors); assert(get_tsp_pstate(tsp_ctx->state) == TSP_PSTATE_SUSPEND); - /* Program the entry point, suspend_level and enter the SP */ + /* Program the entry point, max_off_pwrlvl and enter the SP */ write_ctx_reg(get_gpregs_ctx(&tsp_ctx->cpu_ctx), CTX_GPREG_X0, - suspend_level); + max_off_pwrlvl); cm_set_elr_el3(SECURE, (uint64_t) &tsp_vectors->cpu_resume_entry); rc = tspd_synchronous_sp_entry(tsp_ctx); diff --git a/services/std_svc/psci/psci_suspend.c b/services/std_svc/psci/psci_suspend.c index a158e36f6..675ef9e26 100644 --- a/services/std_svc/psci/psci_suspend.c +++ b/services/std_svc/psci/psci_suspend.c @@ -76,6 +76,8 @@ static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl, entry_point_info_t *ep, psci_power_state_t *state_info) { + unsigned int max_off_lvl = psci_find_max_off_lvl(state_info); + /* Save PSCI target power level for the suspend finisher handler */ psci_set_suspend_pwrlvl(end_pwrlvl); @@ -91,7 +93,7 @@ static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl, * error, it's expected to assert within */ if (psci_spd_pm && psci_spd_pm->svc_suspend) - psci_spd_pm->svc_suspend(0); + psci_spd_pm->svc_suspend(max_off_lvl); /* * Store the re-entry information for the non-secure world. @@ -105,7 +107,7 @@ static void psci_suspend_to_pwrdown_start(unsigned int end_pwrlvl, * TODO : Introduce a mechanism to query the cache level to flush * and the cpu-ops power down to perform from the platform. */ - psci_do_pwrdown_cache_maintenance(psci_find_max_off_lvl(state_info)); + psci_do_pwrdown_cache_maintenance(max_off_lvl); } /******************************************************************************* @@ -213,7 +215,7 @@ void psci_cpu_suspend_finish(unsigned int cpu_idx, psci_power_state_t *state_info) { unsigned long long counter_freq; - unsigned int suspend_level; + unsigned int max_off_lvl; /* Ensure we have been woken up from a suspended state */ assert(psci_get_aff_info_state() == AFF_STATE_ON && is_local_state_off(\ @@ -245,9 +247,9 @@ void psci_cpu_suspend_finish(unsigned int cpu_idx, * error, it's expected to assert within */ if (psci_spd_pm && psci_spd_pm->svc_suspend) { - suspend_level = psci_get_suspend_pwrlvl(); - assert (suspend_level != PSCI_INVALID_PWR_LVL); - psci_spd_pm->svc_suspend_finish(suspend_level); + max_off_lvl = psci_find_max_off_lvl(state_info); + assert (max_off_lvl != PSCI_INVALID_PWR_LVL); + psci_spd_pm->svc_suspend_finish(max_off_lvl); } /* Invalidate the suspend level for the cpu */