mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-16 09:34:18 +00:00
fix(cpus): avoid SME related loss of context on powerdown
Travis' and Gelas' TRMs tell us to disable SME (set PSTATE.{ZA, SM} to 0) when we're attempting to power down. What they don't tell us is that if this isn't done, the powerdown request will be rejected. On the CPU_OFF path that's not a problem - we can force SVCR to 0 and be certain the core will power off. On the suspend to powerdown path, however, we cannot do this. The TRM also tells us that the sequence could also be aborted on eg. GIC interrupts. If this were to happen when we have overwritten SVCR to 0, upon a return to the caller they would experience a loss of context. We know that at least Linux may call into PSCI with SVCR != 0. One option is to save the entire SME context which would be quite expensive just to work around. Another option is to downgrade the request to a normal suspend when SME was left on. This option is better as this is expected to happen rarely enough to ignore the wasted power and we don't want to burden the generic (correct) path with needless context management. Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com> Change-Id: I698fa8490ebf51461f6aa8bba84f9827c5c46ad4
This commit is contained in:
parent
2b5e00d4ea
commit
45c7328c0b
16 changed files with 59 additions and 64 deletions
2
Makefile
2
Makefile
|
@ -1241,6 +1241,7 @@ $(eval $(call assert_booleans,\
|
|||
ENCRYPT_BL31 \
|
||||
ENCRYPT_BL32 \
|
||||
ERRATA_SPECULATIVE_AT \
|
||||
ERRATA_SME_POWER_DOWN \
|
||||
RAS_TRAP_NS_ERR_REC_ACCESS \
|
||||
COT_DESC_IN_DTB \
|
||||
USE_SP804_TIMER \
|
||||
|
@ -1430,6 +1431,7 @@ $(eval $(call add_defines,\
|
|||
BL2_INV_DCACHE \
|
||||
USE_SPINLOCK_CAS \
|
||||
ERRATA_SPECULATIVE_AT \
|
||||
ERRATA_SME_POWER_DOWN \
|
||||
RAS_TRAP_NS_ERR_REC_ACCESS \
|
||||
COT_DESC_IN_DTB \
|
||||
USE_SP804_TIMER \
|
||||
|
|
|
@ -1207,6 +1207,12 @@ Common build options
|
|||
implement this workaround due to the behaviour of the errata mentioned
|
||||
in new SDEN document which will get published soon.
|
||||
|
||||
- ``ERRATA_SME_POWER_DOWN``: Boolean option to disable SME (PSTATE.{ZA,SM}=0)
|
||||
before power down and downgrade a suspend to power down request to a normal
|
||||
suspend request. This is necessary when software running at lower ELs requests
|
||||
power down without first clearing these bits. On affected cores, the CME
|
||||
connected to it will reject its power down request. The default value is 0.
|
||||
|
||||
- ``RAS_TRAP_NS_ERR_REC_ACCESS``: This flag enables/disables the SCR_EL3.TERR
|
||||
bit, to trap access to the RAS ERR and RAS ERX registers from lower ELs.
|
||||
This flag is disabled by default.
|
||||
|
|
|
@ -1139,6 +1139,7 @@
|
|||
******************************************************************************/
|
||||
#define ID_AA64SMFR0_EL1 S3_0_C0_C4_5
|
||||
#define SMCR_EL3 S3_6_C1_C2_6
|
||||
#define SVCR S3_3_C4_C2_2
|
||||
|
||||
/* ID_AA64SMFR0_EL1 definitions */
|
||||
#define ID_AA64SMFR0_EL1_SME_FA64_SHIFT U(63)
|
||||
|
|
|
@ -572,6 +572,7 @@ DEFINE_RENAME_SYSREG_WRITE_FUNC(zcr_el2, ZCR_EL2)
|
|||
|
||||
DEFINE_RENAME_IDREG_READ_FUNC(id_aa64smfr0_el1, ID_AA64SMFR0_EL1)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(smcr_el3, SMCR_EL3)
|
||||
DEFINE_RENAME_SYSREG_RW_FUNCS(svcr, SVCR)
|
||||
|
||||
DEFINE_RENAME_SYSREG_READ_FUNC(erridr_el1, ERRIDR_EL1)
|
||||
DEFINE_RENAME_SYSREG_WRITE_FUNC(errselr_el1, ERRSELR_EL1)
|
||||
|
|
|
@ -20,10 +20,4 @@
|
|||
#define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1 S3_0_C15_C2_7
|
||||
#define CORTEX_ALTO_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
|
||||
|
||||
/*******************************************************************************
|
||||
* SME Control registers
|
||||
******************************************************************************/
|
||||
#define CORTEX_ALTO_SVCRSM S0_3_C4_C2_3
|
||||
#define CORTEX_ALTO_SVCRZA S0_3_C4_C4_3
|
||||
|
||||
#endif /* CORTEX_ALTO_H */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -22,10 +22,4 @@
|
|||
#define CORTEX_GELAS_CPUPWRCTLR_EL1 S3_0_C15_C2_7
|
||||
#define CORTEX_GELAS_CPUPWRCTLR_EL1_CORE_PWRDN_BIT U(1)
|
||||
|
||||
/*******************************************************************************
|
||||
* SME Control registers
|
||||
******************************************************************************/
|
||||
#define CORTEX_GELAS_SVCRSM S0_3_C4_C2_3
|
||||
#define CORTEX_GELAS_SVCRZA S0_3_C4_C4_3
|
||||
|
||||
#endif /* CORTEX_GELAS_H */
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2023, Arm Limited. All rights reserved.
|
||||
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -20,10 +20,4 @@
|
|||
#define TRAVIS_IMP_CPUPWRCTLR_EL1 S3_0_C15_C2_7
|
||||
#define TRAVIS_IMP_CPUPWRCTLR_EL1_CORE_PWRDN_EN_BIT U(1)
|
||||
|
||||
/*******************************************************************************
|
||||
* SME Control registers
|
||||
******************************************************************************/
|
||||
#define TRAVIS_SVCRSM S0_3_C4_C2_3
|
||||
#define TRAVIS_SVCRZA S0_3_C4_C4_3
|
||||
|
||||
#endif /* TRAVIS_H */
|
||||
|
|
|
@ -21,26 +21,16 @@
|
|||
#error "Alto supports only AArch64. Compile with CTX_INCLUDE_AARCH32_REGS=0"
|
||||
#endif
|
||||
|
||||
#if ERRATA_SME_POWER_DOWN == 0
|
||||
#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
|
||||
#endif
|
||||
|
||||
cpu_reset_func_start cortex_alto
|
||||
/* Disable speculative loads */
|
||||
msr SSBS, xzr
|
||||
cpu_reset_func_end cortex_alto
|
||||
|
||||
func cortex_alto_core_pwr_dwn
|
||||
#if ENABLE_SME_FOR_NS
|
||||
/* ---------------------------------------------------
|
||||
* Disable SME if enabled and supported
|
||||
* ---------------------------------------------------
|
||||
*/
|
||||
mrs x0, ID_AA64PFR1_EL1
|
||||
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
|
||||
#ID_AA64PFR1_EL1_SME_WIDTH
|
||||
cmp x0, #SME_NOT_IMPLEMENTED
|
||||
b.eq 1f
|
||||
msr CORTEX_ALTO_SVCRSM, xzr
|
||||
msr CORTEX_ALTO_SVCRZA, xzr
|
||||
1:
|
||||
#endif
|
||||
/* ---------------------------------------------------
|
||||
* Enable CPU power down bit in power control register
|
||||
* ---------------------------------------------------
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#error "Gelas must be compiled with FEAT_PABANDON enabled"
|
||||
#endif
|
||||
|
||||
#if ERRATA_SME_POWER_DOWN == 0
|
||||
#error "Gelas needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
|
||||
#endif
|
||||
|
||||
cpu_reset_func_start cortex_gelas
|
||||
/* ----------------------------------------------------
|
||||
* Disable speculative loads
|
||||
|
@ -38,20 +42,6 @@ cpu_reset_func_end cortex_gelas
|
|||
* ----------------------------------------------------
|
||||
*/
|
||||
func cortex_gelas_core_pwr_dwn
|
||||
#if ENABLE_SME_FOR_NS
|
||||
/* ---------------------------------------------------
|
||||
* Disable SME if enabled and supported
|
||||
* ---------------------------------------------------
|
||||
*/
|
||||
mrs x0, ID_AA64PFR1_EL1
|
||||
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
|
||||
#ID_AA64PFR1_EL1_SME_WIDTH
|
||||
cmp x0, #SME_NOT_IMPLEMENTED
|
||||
b.eq 1f
|
||||
msr CORTEX_GELAS_SVCRSM, xzr
|
||||
msr CORTEX_GELAS_SVCRZA, xzr
|
||||
1:
|
||||
#endif
|
||||
/* ---------------------------------------------------
|
||||
* Flip CPU power down bit in power control register.
|
||||
* It will be set on powerdown and cleared on wakeup
|
||||
|
|
|
@ -25,6 +25,10 @@
|
|||
#error "Travis must be compiled with FEAT_PABANDON enabled"
|
||||
#endif
|
||||
|
||||
#if ERRATA_SME_POWER_DOWN == 0
|
||||
#error "Travis needs ERRATA_SME_POWER_DOWN=1 to powerdown correctly"
|
||||
#endif
|
||||
|
||||
cpu_reset_func_start travis
|
||||
/* ----------------------------------------------------
|
||||
* Disable speculative loads
|
||||
|
@ -34,20 +38,6 @@ cpu_reset_func_start travis
|
|||
cpu_reset_func_end travis
|
||||
|
||||
func travis_core_pwr_dwn
|
||||
#if ENABLE_SME_FOR_NS
|
||||
/* ---------------------------------------------------
|
||||
* Disable SME if enabled and supported
|
||||
* ---------------------------------------------------
|
||||
*/
|
||||
mrs x0, ID_AA64PFR1_EL1
|
||||
ubfx x0, x0, #ID_AA64PFR1_EL1_SME_SHIFT, \
|
||||
#ID_AA64PFR1_EL1_SME_WIDTH
|
||||
cmp x0, #SME_NOT_IMPLEMENTED
|
||||
b.eq 1f
|
||||
msr TRAVIS_SVCRSM, xzr
|
||||
msr TRAVIS_SVCRZA, xzr
|
||||
1:
|
||||
#endif
|
||||
/* ---------------------------------------------------
|
||||
* Flip CPU power down bit in power control register.
|
||||
* It will be set on powerdown and cleared on wakeup
|
||||
|
|
|
@ -1206,6 +1206,18 @@ void psci_pwrdown_cpu_start(unsigned int power_level)
|
|||
******************************************************************************/
|
||||
void __dead2 psci_pwrdown_cpu_end_terminal(void)
|
||||
{
|
||||
#if ERRATA_SME_POWER_DOWN
|
||||
/*
|
||||
* force SME off to not get power down rejected. Getting here is
|
||||
* terminal so we don't care if we lose context because of another
|
||||
* wakeup
|
||||
*/
|
||||
if (is_feat_sme_supported()) {
|
||||
write_svcr(0);
|
||||
isb();
|
||||
}
|
||||
#endif /* ERRATA_SME_POWER_DOWN */
|
||||
|
||||
/*
|
||||
* Execute a wfi which, in most cases, will allow the power controller
|
||||
* to physically power down this cpu. Under some circumstances that may
|
||||
|
|
|
@ -1,5 +1,5 @@
|
|||
/*
|
||||
* Copyright (c) 2013-2022, Arm Limited and Contributors. All rights reserved.
|
||||
* Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
|
||||
*
|
||||
* SPDX-License-Identifier: BSD-3-Clause
|
||||
*/
|
||||
|
@ -8,6 +8,7 @@
|
|||
#include <string.h>
|
||||
|
||||
#include <arch.h>
|
||||
#include <arch_features.h>
|
||||
#include <arch_helpers.h>
|
||||
#include <common/debug.h>
|
||||
#include <lib/pmf/pmf.h>
|
||||
|
@ -64,6 +65,19 @@ int psci_cpu_suspend(unsigned int power_state,
|
|||
plat_local_state_t prev[PLAT_MAX_PWR_LVL];
|
||||
#endif
|
||||
|
||||
#if ERRATA_SME_POWER_DOWN
|
||||
/*
|
||||
* If SME isn't off, attempting a real power down will only end up being
|
||||
* rejected. If we got called with SME on, fall back to a normal
|
||||
* suspend. We can't force SME off as in the event the power down is
|
||||
* rejected for another reason (eg GIC) we'd lose the SME context.
|
||||
*/
|
||||
if (is_feat_sme_supported() && read_svcr() != 0) {
|
||||
power_state &= ~(PSTATE_TYPE_MASK << PSTATE_TYPE_SHIFT);
|
||||
power_state &= ~(PSTATE_PWR_LVL_MASK << PSTATE_PWR_LVL_SHIFT);
|
||||
}
|
||||
#endif /* ERRATA_SME_POWER_DOWN */
|
||||
|
||||
/* Validate the power_state parameter */
|
||||
rc = psci_validate_power_state(power_state, &state_info);
|
||||
if (rc != PSCI_E_SUCCESS) {
|
||||
|
|
|
@ -93,7 +93,7 @@ int psci_do_cpu_off(unsigned int end_pwrlvl)
|
|||
*/
|
||||
if ((psci_spd_pm != NULL) && (psci_spd_pm->svc_off != NULL)) {
|
||||
rc = psci_spd_pm->svc_off(0);
|
||||
if (rc != 0)
|
||||
if (rc != PSCI_E_SUCCESS)
|
||||
goto exit;
|
||||
}
|
||||
|
||||
|
|
|
@ -347,6 +347,9 @@ SUPPORT_STACK_MEMTAG := no
|
|||
# Select workaround for AT speculative behaviour.
|
||||
ERRATA_SPECULATIVE_AT := 0
|
||||
|
||||
# select workaround for SME aborting powerdown
|
||||
ERRATA_SME_POWER_DOWN := 0
|
||||
|
||||
# Trap RAS error record access from Non secure
|
||||
RAS_TRAP_NS_ERR_REC_ACCESS := 0
|
||||
|
||||
|
|
|
@ -221,7 +221,9 @@ endif
|
|||
|
||||
#Build AArch64-only CPUs with no FVP model yet.
|
||||
ifeq (${BUILD_CPUS_WITH_NO_FVP_MODEL},1)
|
||||
# travis/gelas need these
|
||||
FEAT_PABANDON := 1
|
||||
ERRATA_SME_POWER_DOWN := 1
|
||||
FVP_CPU_LIBS += lib/cpus/aarch64/neoverse_n3.S \
|
||||
lib/cpus/aarch64/cortex_gelas.S \
|
||||
lib/cpus/aarch64/nevis.S \
|
||||
|
|
|
@ -150,6 +150,8 @@ endif
|
|||
# CPU libraries for TARGET_PLATFORM=4
|
||||
ifeq (${TARGET_PLATFORM}, 4)
|
||||
FEAT_PABANDON := 1
|
||||
# prevent CME related wakups
|
||||
ERRATA_SME_POWER_DOWN := 1
|
||||
TC_CPU_SOURCES += lib/cpus/aarch64/cortex_gelas.S \
|
||||
lib/cpus/aarch64/nevis.S \
|
||||
lib/cpus/aarch64/travis.S
|
||||
|
|
Loading…
Add table
Reference in a new issue