fix(spe): add a psb before updating context and remove context saving

In the chapter about FEAT_SPE (D16.4 specifically) it is stated that
"Sampling is always disabled at EL3". That means that disabling sampling
(writing PMBLIMITR_EL1.E to 0) is redundant and can be removed. The only
reason we save/restore SPE context is because of that disable, so those
can be removed too.

There's the issue of draining the profiling buffer though. No new
samples will have been generated since entering EL3. However, old
samples might still be in-flight. Unless synchronised by a psb csync,
those might be affected by our extensive context mutation. Adding a psb
in prepare_el3_entry should cater for that. Note that prior to the
introduction of root context this was not a problem as context remained
unchanged and the hooks took care of the rest.

Then, the only time we care about the buffer actually making it to
memory is when we exit coherency. On HW_ASSISTED_COHERENCY systems we
don't have to do anything, it should be handled for us. Systems without
it need a dsb to wait for them to complete. There should be one already
in each cpu's powerdown hook which should work.

While on the topic of barriers, the esb barrier is no longer used.
Remove it.

Change-Id: I9736fc7d109702c63e7d403dc9e2a4272828afb2
Signed-off-by: Boyan Karatotev <boyan.karatotev@arm.com>
This commit is contained in:
Boyan Karatotev 2024-11-21 13:55:59 +00:00
parent 3c72b2ab0b
commit f808873372
5 changed files with 13 additions and 106 deletions

View file

@ -1,5 +1,5 @@
/*
* Copyright (c) 2013-2020, ARM Limited and Contributors. All rights reserved.
* Copyright (c) 2013-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@ -224,13 +224,6 @@
.space SPINLOCK_ASM_SIZE
.endm
/*
* With RAS extension executes esb instruction, else NOP
*/
.macro esb
.inst 0xd503221f
.endm
/*
* Helper macro to read system register value into x0
*/
@ -265,6 +258,10 @@
msr SYSREG_SB, xzr
.endm
.macro psb_csync
hint #17 /* use the hint synonym for compatibility */
.endm
/*
* Macro for using speculation barrier instruction introduced by
* FEAT_SB, if it's enabled.

View file

@ -14,7 +14,6 @@
void spe_enable(cpu_context_t *ctx);
void spe_disable(cpu_context_t *ctx);
void spe_init_el2_unused(void);
void spe_stop(void);
#else
static inline void spe_enable(cpu_context_t *ctx)
{
@ -25,9 +24,6 @@ static inline void spe_disable(cpu_context_t *ctx)
static inline void spe_init_el2_unused(void)
{
}
static inline void spe_stop(void)
{
}
#endif /* ENABLE_SPE_FOR_NS */
#endif /* SPE_H */

View file

@ -440,6 +440,14 @@ no_mpam:
* -----------------------------------------------------------------
*/
func prepare_el3_entry
/*
* context is about to mutate, so make sure we don't affect any still
* in-flight profiling operations. We don't care that they actually
* finish, that can still be later. NOP if not present
*/
#if ENABLE_SPE_FOR_NS
psb_csync
#endif
save_gp_pmcr_pauth_regs
setup_el3_execution_context
ret

View file

@ -14,21 +14,6 @@
#include <plat/common/platform.h>
typedef struct spe_ctx {
u_register_t pmblimitr_el1;
} spe_ctx_t;
static struct spe_ctx spe_ctxs[PLATFORM_CORE_COUNT];
static inline void psb_csync(void)
{
/*
* The assembler does not yet understand the psb csync mnemonic
* so use the equivalent hint instruction.
*/
__asm__ volatile("hint #17");
}
void spe_enable(cpu_context_t *ctx)
{
el3_state_t *state = get_el3state_ctx(ctx);
@ -90,63 +75,3 @@ void spe_init_el2_unused(void)
v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
write_mdcr_el2(v);
}
void spe_stop(void)
{
uint64_t v;
/* Drain buffered data */
psb_csync();
dsbnsh();
/* Disable profiling buffer */
v = read_pmblimitr_el1();
v &= ~(1ULL << 0);
write_pmblimitr_el1(v);
isb();
}
static void *spe_drain_buffers_hook(const void *arg)
{
if (!is_feat_spe_supported())
return (void *)-1;
/* Drain buffered data */
psb_csync();
dsbnsh();
return (void *)0;
}
static void *spe_context_save(const void *arg)
{
unsigned int core_pos;
struct spe_ctx *ctx;
if (is_feat_spe_supported()) {
core_pos = plat_my_core_pos();
ctx = &spe_ctxs[core_pos];
ctx->pmblimitr_el1 = read_pmblimitr_el1();
}
return NULL;
}
static void *spe_context_restore(const void *arg)
{
unsigned int core_pos;
struct spe_ctx *ctx;
if (is_feat_spe_supported()) {
core_pos = plat_my_core_pos();
ctx = &spe_ctxs[core_pos];
write_pmblimitr_el1(ctx->pmblimitr_el1);
}
return NULL;
}
SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook);
SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, spe_context_save);
SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, spe_context_restore);

View file

@ -1169,8 +1169,6 @@ int psci_secondaries_brought_up(void)
******************************************************************************/
void psci_pwrdown_cpu(unsigned int power_level)
{
psci_do_manage_extensions();
#if HW_ASSISTED_COHERENCY
/*
* With hardware-assisted coherency, the CPU drivers only initiate the
@ -1290,20 +1288,3 @@ bool psci_are_all_cpus_on_safe(void)
return true;
}
/*******************************************************************************
* This function performs architectural feature specific management.
* It ensures the architectural features are disabled during cpu
* power off/suspend operations.
******************************************************************************/
void psci_do_manage_extensions(void)
{
/*
* On power down we need to disable statistical profiling extensions
* before exiting coherency.
*/
if (is_feat_spe_supported()) {
spe_stop();
}
}