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:
Boyan Karatotev 2024-09-20 13:37:51 +01:00
parent 2b5e00d4ea
commit 45c7328c0b
16 changed files with 59 additions and 64 deletions

View file

@ -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 \

View file

@ -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.

View file

@ -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)

View file

@ -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)

View file

@ -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 */

View file

@ -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 */

View file

@ -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 */

View file

@ -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
* ---------------------------------------------------

View file

@ -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

View file

@ -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

View file

@ -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

View file

@ -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) {

View file

@ -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;
}

View file

@ -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

View file

@ -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 \

View file

@ -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