mirror of
https://github.com/ARM-software/arm-trusted-firmware.git
synced 2025-04-18 10:34:19 +00:00

spe_disable function, disables profiling and flushes all the buffers and hence needs to be called on power-off/suspend path. It needs to be invoked as SPE feature writes to memory as part of regular operation and not disabling before exiting coherency could potentially cause issues. Currently, this is handled only for the FVP. Other platforms need to replicate this behaviour and is covered as part of this patch. Calling it from generic psci library code, before the platform specific actions to turn off the CPUs, will make it applicable for all the platforms which have ported the PSCI library. Change-Id: I90b24c59480357e2ebfa3dfc356c719ca935c13d Signed-off-by: Jayanth Dodderi Chidanand <jayanthdodderi.chidanand@arm.com>
131 lines
2.8 KiB
C
131 lines
2.8 KiB
C
/*
|
|
* Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
|
|
*
|
|
* SPDX-License-Identifier: BSD-3-Clause
|
|
*/
|
|
|
|
#include <stdbool.h>
|
|
|
|
#include <arch.h>
|
|
#include <arch_features.h>
|
|
#include <arch_helpers.h>
|
|
#include <lib/el3_runtime/pubsub.h>
|
|
#include <lib/extensions/spe.h>
|
|
|
|
#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_init_el3(void)
|
|
{
|
|
uint64_t v;
|
|
|
|
/*
|
|
* MDCR_EL3.NSPB (ARM v8.2): SPE enabled in Non-secure state
|
|
* and disabled in secure state. Accesses to SPE registers at
|
|
* S-EL1 generate trap exceptions to EL3.
|
|
*
|
|
* MDCR_EL3.NSPBE: Profiling Buffer uses Non-secure Virtual Addresses.
|
|
* When FEAT_RME is not implemented, this field is RES0.
|
|
*
|
|
* MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1
|
|
* register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented.
|
|
* Setting this bit to 1 doesn't have any effect on it when
|
|
* FEAT_SPEv1p2 not implemented.
|
|
*/
|
|
v = read_mdcr_el3();
|
|
v |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT;
|
|
v &= ~(MDCR_NSPBE_BIT);
|
|
write_mdcr_el3(v);
|
|
}
|
|
|
|
void spe_init_el2_unused(void)
|
|
{
|
|
uint64_t v;
|
|
|
|
/*
|
|
* MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical
|
|
* profiling controls to EL2.
|
|
*
|
|
* MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure
|
|
* state. Accesses to profiling buffer controls at
|
|
* Non-secure EL1 are not trapped to EL2.
|
|
*/
|
|
v = read_mdcr_el2();
|
|
v &= ~MDCR_EL2_TPMS;
|
|
v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1);
|
|
write_mdcr_el2(v);
|
|
}
|
|
|
|
void spe_disable(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);
|