mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-27 23:35:10 +00:00
Fix broken standby state implementation in PSCI
This patch fixes the broken support for entry into standby states introduced under commit-id 'd118f9f864' (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
This commit is contained in:
parent
60bc4bbd0b
commit
317ba09021
3 changed files with 47 additions and 20 deletions
|
@ -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 @@
|
||||||
.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
|
||||||
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
|
||||||
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
|
||||||
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,
|
||||||
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)
|
||||||
*/
|
*/
|
||||||
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;
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue