1 /* 2 * Copyright (c) 2017-2024, Arm Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <stdbool.h> 8 9 #include <arch.h> 10 #include <arch_features.h> 11 #include <arch_helpers.h> 12 #include <lib/el3_runtime/pubsub.h> 13 #include <lib/extensions/spe.h> 14 15 #include <plat/common/platform.h> 16 17 typedef struct spe_ctx { 18 u_register_t pmblimitr_el1; 19 } spe_ctx_t; 20 21 static struct spe_ctx spe_ctxs[PLATFORM_CORE_COUNT]; 22 psb_csync(void)23static inline void psb_csync(void) 24 { 25 /* 26 * The assembler does not yet understand the psb csync mnemonic 27 * so use the equivalent hint instruction. 28 */ 29 __asm__ volatile("hint #17"); 30 } 31 spe_init_el3(void)32void spe_init_el3(void) 33 { 34 uint64_t v; 35 36 /* 37 * MDCR_EL3.NSPB (ARM v8.2): SPE enabled in Non-secure state 38 * and disabled in secure state. Accesses to SPE registers at 39 * S-EL1 generate trap exceptions to EL3. 40 * 41 * MDCR_EL3.NSPBE: Profiling Buffer uses Non-secure Virtual Addresses. 42 * When FEAT_RME is not implemented, this field is RES0. 43 * 44 * MDCR_EL3.EnPMSN (ARM v8.7): Do not trap access to PMSNEVFR_EL1 45 * register at NS-EL1 or NS-EL2 to EL3 if FEAT_SPEv1p2 is implemented. 46 * Setting this bit to 1 doesn't have any effect on it when 47 * FEAT_SPEv1p2 not implemented. 48 */ 49 v = read_mdcr_el3(); 50 v |= MDCR_NSPB(MDCR_NSPB_EL1) | MDCR_EnPMSN_BIT; 51 v &= ~(MDCR_NSPBE_BIT); 52 write_mdcr_el3(v); 53 } 54 spe_init_el2_unused(void)55void spe_init_el2_unused(void) 56 { 57 uint64_t v; 58 59 /* 60 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 61 * profiling controls to EL2. 62 * 63 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 64 * state. Accesses to profiling buffer controls at 65 * Non-secure EL1 are not trapped to EL2. 66 */ 67 v = read_mdcr_el2(); 68 v &= ~MDCR_EL2_TPMS; 69 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 70 write_mdcr_el2(v); 71 } 72 spe_disable(void)73void spe_disable(void) 74 { 75 uint64_t v; 76 77 /* Drain buffered data */ 78 psb_csync(); 79 dsbnsh(); 80 81 /* Disable profiling buffer */ 82 v = read_pmblimitr_el1(); 83 v &= ~(1ULL << 0); 84 write_pmblimitr_el1(v); 85 isb(); 86 } 87 spe_drain_buffers_hook(const void * arg)88static void *spe_drain_buffers_hook(const void *arg) 89 { 90 if (!is_feat_spe_supported()) 91 return (void *)-1; 92 93 /* Drain buffered data */ 94 psb_csync(); 95 dsbnsh(); 96 97 return (void *)0; 98 } 99 spe_context_save(const void * arg)100static void *spe_context_save(const void *arg) 101 { 102 unsigned int core_pos; 103 struct spe_ctx *ctx; 104 105 if (is_feat_spe_supported()) { 106 core_pos = plat_my_core_pos(); 107 ctx = &spe_ctxs[core_pos]; 108 ctx->pmblimitr_el1 = read_pmblimitr_el1(); 109 } 110 111 return NULL; 112 } 113 spe_context_restore(const void * arg)114static void *spe_context_restore(const void *arg) 115 { 116 unsigned int core_pos; 117 struct spe_ctx *ctx; 118 119 if (is_feat_spe_supported()) { 120 core_pos = plat_my_core_pos(); 121 ctx = &spe_ctxs[core_pos]; 122 write_pmblimitr_el1(ctx->pmblimitr_el1); 123 } 124 125 return NULL; 126 } 127 128 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 129 130 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, spe_context_save); 131 SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, spe_context_restore); 132