fix(spe): invoke spe_disable during power domain off/suspend
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>
diff --git a/lib/extensions/spe/spe.c b/lib/extensions/spe/spe.c
index 2c25a9d..d1fb182 100644
--- a/lib/extensions/spe/spe.c
+++ b/lib/extensions/spe/spe.c
@@ -1,5 +1,5 @@
/*
- * Copyright (c) 2017-2023, Arm Limited and Contributors. All rights reserved.
+ * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
@@ -12,6 +12,14 @@
#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)
{
/*
@@ -89,4 +97,35 @@
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);