Commit 317ba090 authored by Achin Gupta's avatar Achin Gupta
Browse files

Fix broken standby state implementation in PSCI

This patch fixes the broken support for entry into standby states
introduced under commit-id 'd118f9f8' (tf-issues#94). Upon exit from
the platform defined standby state instead of returning to the caller
of the SMC, execution would get stuck in the wfi instruction meant for
entering a power down state. This patch ensures that exit from a
standby state and entry into a power down state do not interfere with
each other.

Fixes ARM-software/tf-issues#154

Change-Id: I56e5df353368e44d6eefc94ffedefe21929f5cfe
parent 60bc4bbd
...@@ -190,6 +190,7 @@ extern void psci_system_reset(void); ...@@ -190,6 +190,7 @@ extern void psci_system_reset(void);
extern int psci_cpu_on(unsigned long, extern int psci_cpu_on(unsigned long,
unsigned long, unsigned long,
unsigned long); unsigned long);
extern void __dead2 psci_power_down_wfi(void);
extern void psci_aff_on_finish_entry(void); extern void psci_aff_on_finish_entry(void);
extern void psci_aff_suspend_finish_entry(void); extern void psci_aff_suspend_finish_entry(void);
extern void psci_register_spd_pm_hook(const spd_pm_ops_t *); extern void psci_register_spd_pm_hook(const spd_pm_ops_t *);
......
...@@ -37,6 +37,7 @@ ...@@ -37,6 +37,7 @@
.globl psci_aff_suspend_finish_entry .globl psci_aff_suspend_finish_entry
.globl __psci_cpu_off .globl __psci_cpu_off
.globl __psci_cpu_suspend .globl __psci_cpu_suspend
.globl psci_power_down_wfi
/* ----------------------------------------------------- /* -----------------------------------------------------
* This cpu has been physically powered up. Depending * This cpu has been physically powered up. Depending
...@@ -120,9 +121,6 @@ func __psci_cpu_off ...@@ -120,9 +121,6 @@ func __psci_cpu_off
mrs x0, mpidr_el1 mrs x0, mpidr_el1
bl platform_set_coherent_stack bl platform_set_coherent_stack
bl psci_cpu_off bl psci_cpu_off
mov x1, #PSCI_E_SUCCESS
cmp x0, x1
b.eq final_wfi
mov sp, x19 mov sp, x19
ldp x19, x20, [sp,#0] ldp x19, x20, [sp,#0]
add sp, sp, #0x10 add sp, sp, #0x10
...@@ -144,9 +142,6 @@ func __psci_cpu_suspend ...@@ -144,9 +142,6 @@ func __psci_cpu_suspend
mov x1, x21 mov x1, x21
mov x2, x22 mov x2, x22
bl psci_cpu_suspend bl psci_cpu_suspend
mov x1, #PSCI_E_SUCCESS
cmp x0, x1
b.eq final_wfi
mov sp, x19 mov sp, x19
ldp x21, x22, [sp,#0x10] ldp x21, x22, [sp,#0x10]
ldp x19, x20, [sp,#0] ldp x19, x20, [sp,#0]
...@@ -154,7 +149,16 @@ func __psci_cpu_suspend ...@@ -154,7 +149,16 @@ func __psci_cpu_suspend
func_epilogue func_epilogue
ret ret
func final_wfi /* --------------------------------------------
* This function is called to indicate to the
* power controller that it is safe to power
* down this cpu. It should not exit the wfi
* and will be released from reset upon power
* up. 'wfi_spill' is used to catch erroneous
* exits from wfi.
* --------------------------------------------
*/
func psci_power_down_wfi
dsb sy // ensure write buffer empty dsb sy // ensure write buffer empty
wfi wfi
wfi_spill: wfi_spill:
......
...@@ -90,23 +90,37 @@ int psci_cpu_suspend(unsigned int power_state, ...@@ -90,23 +90,37 @@ int psci_cpu_suspend(unsigned int power_state,
if (target_afflvl > MPIDR_MAX_AFFLVL) if (target_afflvl > MPIDR_MAX_AFFLVL)
return PSCI_E_INVALID_PARAMS; return PSCI_E_INVALID_PARAMS;
/* Determine the 'state type' in the 'power_state' parameter */
pstate_type = psci_get_pstate_type(power_state); pstate_type = psci_get_pstate_type(power_state);
/*
* Ensure that we have a platform specific handler for entering
* a standby state.
*/
if (pstate_type == PSTATE_TYPE_STANDBY) { if (pstate_type == PSTATE_TYPE_STANDBY) {
if (psci_plat_pm_ops->affinst_standby) if (!psci_plat_pm_ops->affinst_standby)
rc = psci_plat_pm_ops->affinst_standby(power_state);
else
return PSCI_E_INVALID_PARAMS; return PSCI_E_INVALID_PARAMS;
} else {
mpidr = read_mpidr(); rc = psci_plat_pm_ops->affinst_standby(power_state);
rc = psci_afflvl_suspend(mpidr, assert(rc == PSCI_E_INVALID_PARAMS || rc == PSCI_E_SUCCESS);
entrypoint, return rc;
context_id,
power_state,
MPIDR_AFFLVL0,
target_afflvl);
} }
assert(rc == PSCI_E_INVALID_PARAMS || rc == PSCI_E_SUCCESS); /*
* Do what is needed to enter the power down state. Upon success,
* enter the final wfi which will power down this cpu else return
* an error.
*/
mpidr = read_mpidr();
rc = psci_afflvl_suspend(mpidr,
entrypoint,
context_id,
power_state,
MPIDR_AFFLVL0,
target_afflvl);
if (rc == PSCI_E_SUCCESS)
psci_power_down_wfi();
assert(rc == PSCI_E_INVALID_PARAMS);
return rc; return rc;
} }
...@@ -126,11 +140,19 @@ int psci_cpu_off(void) ...@@ -126,11 +140,19 @@ int psci_cpu_off(void)
*/ */
rc = psci_afflvl_off(mpidr, MPIDR_AFFLVL0, target_afflvl); rc = psci_afflvl_off(mpidr, MPIDR_AFFLVL0, target_afflvl);
/*
* Check if all actions needed to safely power down this cpu have
* successfully completed. Enter a wfi loop which will allow the
* power controller to physically power down this cpu.
*/
if (rc == PSCI_E_SUCCESS)
psci_power_down_wfi();
/* /*
* The only error cpu_off can return is E_DENIED. So check if that's * The only error cpu_off can return is E_DENIED. So check if that's
* indeed the case. * indeed the case.
*/ */
assert (rc == PSCI_E_SUCCESS || rc == PSCI_E_DENIED); assert (rc == PSCI_E_DENIED);
return rc; return rc;
} }
......
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