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 12 /* 13 * The assembler does not yet understand the psb csync mnemonic 14 * so use the equivalent hint instruction. 15 */ 16 #define psb_csync() asm volatile("hint #17") 17 18 void spe_enable(int el2_unused) 19 { 20 uint64_t features; 21 22 features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 23 if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 24 uint64_t v; 25 26 if (el2_unused) { 27 /* 28 * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 29 * profiling controls to EL2. 30 * 31 * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 32 * state. Accesses to profiling buffer controls at 33 * Non-secure EL1 are not trapped to EL2. 34 */ 35 v = read_mdcr_el2(); 36 v &= ~MDCR_EL2_TPMS; 37 v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 38 write_mdcr_el2(v); 39 } 40 41 /* 42 * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 43 * and disabled in secure state. Accesses to SPE registers at 44 * S-EL1 generate trap exceptions to EL3. 45 */ 46 v = read_mdcr_el3(); 47 v |= MDCR_NSPB(MDCR_NSPB_EL1); 48 write_mdcr_el3(v); 49 } 50 } 51 52 void spe_disable(void) 53 { 54 uint64_t features; 55 56 features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 57 if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 58 uint64_t v; 59 60 /* Drain buffered data */ 61 psb_csync(); 62 dsbnsh(); 63 64 /* Disable profiling buffer */ 65 v = read_pmblimitr_el1(); 66 v &= ~(1ULL << 0); 67 write_pmblimitr_el1(v); 68 isb(); 69 } 70 } 71 72 static void *spe_drain_buffers_hook(const void *arg) 73 { 74 uint64_t features; 75 76 features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 77 if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 78 /* Drain buffered data */ 79 psb_csync(); 80 dsbnsh(); 81 } 82 83 return 0; 84 } 85 86 SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 87