1 /* 2 * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3 * 4 * SPDX-License-Identifier: BSD-3-Clause 5 */ 6 7 #include <arch.h> 8 #include <arch_helpers.h> 9 #include <pubsub.h> 10 #include <spe.h> 11 #include <stdbool.h> 12 13 static inline void psb_csync(void) 14 { 15 /* 16 * The assembler does not yet understand the psb csync mnemonic 17 * so use the equivalent hint instruction. 18 */ 19 __asm__ volatile("hint #17"); 20 } 21 22 bool spe_supported(void) 23 { 24 uint64_t features; 25 26 features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 27 return (features & ID_AA64DFR0_PMS_MASK) == 1U; 28 } 29 30 void spe_enable(bool el2_unused) 31 { 32 uint64_t v; 33 34 if (!spe_supported()) 35 return; 36 37 if (el2_unused) { 38 /* 39 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 40 * profiling controls to EL2. 41 * 42 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 43 * state. Accesses to profiling buffer controls at 44 * Non-secure EL1 are not trapped to EL2. 45 */ 46 v = read_mdcr_el2(); 47 v &= ~MDCR_EL2_TPMS; 48 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 49 write_mdcr_el2(v); 50 } 51 52 /* 53 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 54 * and disabled in secure state. Accesses to SPE registers at 55 * S-EL1 generate trap exceptions to EL3. 56 */ 57 v = read_mdcr_el3(); 58 v |= MDCR_NSPB(MDCR_NSPB_EL1); 59 write_mdcr_el3(v); 60 } 61 62 void spe_disable(void) 63 { 64 uint64_t v; 65 66 if (!spe_supported()) 67 return; 68 69 /* Drain buffered data */ 70 psb_csync(); 71 dsbnsh(); 72 73 /* Disable profiling buffer */ 74 v = read_pmblimitr_el1(); 75 v &= ~(1ULL << 0); 76 write_pmblimitr_el1(v); 77 isb(); 78 } 79 80 static void *spe_drain_buffers_hook(const void *arg) 81 { 82 if (!spe_supported()) 83 return (void *)-1; 84 85 /* Drain buffered data */ 86 psb_csync(); 87 dsbnsh(); 88 89 return (void *)0; 90 } 91 92 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 93