1281a08ccSDimitris Papastamos /* 2*2ff8fbf3SDimitris Papastamos * Copyright (c) 2017-2018, ARM Limited and Contributors. All rights reserved. 3281a08ccSDimitris Papastamos * 4281a08ccSDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5281a08ccSDimitris Papastamos */ 6281a08ccSDimitris Papastamos 7281a08ccSDimitris Papastamos #include <arch.h> 8281a08ccSDimitris Papastamos #include <arch_helpers.h> 9281a08ccSDimitris Papastamos #include <pubsub.h> 10281a08ccSDimitris Papastamos 11281a08ccSDimitris Papastamos /* 12281a08ccSDimitris Papastamos * The assembler does not yet understand the psb csync mnemonic 13281a08ccSDimitris Papastamos * so use the equivalent hint instruction. 14281a08ccSDimitris Papastamos */ 15281a08ccSDimitris Papastamos #define psb_csync() asm volatile("hint #17") 16281a08ccSDimitris Papastamos 17*2ff8fbf3SDimitris Papastamos int spe_supported(void) 18281a08ccSDimitris Papastamos { 19281a08ccSDimitris Papastamos uint64_t features; 20281a08ccSDimitris Papastamos 21281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 22*2ff8fbf3SDimitris Papastamos return (features & ID_AA64DFR0_PMS_MASK) == 1; 23*2ff8fbf3SDimitris Papastamos } 24*2ff8fbf3SDimitris Papastamos 25*2ff8fbf3SDimitris Papastamos void spe_enable(int el2_unused) 26*2ff8fbf3SDimitris Papastamos { 27281a08ccSDimitris Papastamos uint64_t v; 28281a08ccSDimitris Papastamos 29*2ff8fbf3SDimitris Papastamos if (!spe_supported()) 30*2ff8fbf3SDimitris Papastamos return; 31*2ff8fbf3SDimitris Papastamos 32281a08ccSDimitris Papastamos if (el2_unused) { 33281a08ccSDimitris Papastamos /* 34281a08ccSDimitris Papastamos * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 35281a08ccSDimitris Papastamos * profiling controls to EL2. 36281a08ccSDimitris Papastamos * 37281a08ccSDimitris Papastamos * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 38281a08ccSDimitris Papastamos * state. Accesses to profiling buffer controls at 39281a08ccSDimitris Papastamos * Non-secure EL1 are not trapped to EL2. 40281a08ccSDimitris Papastamos */ 41281a08ccSDimitris Papastamos v = read_mdcr_el2(); 42281a08ccSDimitris Papastamos v &= ~MDCR_EL2_TPMS; 43281a08ccSDimitris Papastamos v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 44281a08ccSDimitris Papastamos write_mdcr_el2(v); 45281a08ccSDimitris Papastamos } 46281a08ccSDimitris Papastamos 47281a08ccSDimitris Papastamos /* 48281a08ccSDimitris Papastamos * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 49281a08ccSDimitris Papastamos * and disabled in secure state. Accesses to SPE registers at 50281a08ccSDimitris Papastamos * S-EL1 generate trap exceptions to EL3. 51281a08ccSDimitris Papastamos */ 52281a08ccSDimitris Papastamos v = read_mdcr_el3(); 53281a08ccSDimitris Papastamos v |= MDCR_NSPB(MDCR_NSPB_EL1); 54281a08ccSDimitris Papastamos write_mdcr_el3(v); 55281a08ccSDimitris Papastamos } 56281a08ccSDimitris Papastamos 57281a08ccSDimitris Papastamos void spe_disable(void) 58281a08ccSDimitris Papastamos { 59281a08ccSDimitris Papastamos uint64_t v; 60281a08ccSDimitris Papastamos 61*2ff8fbf3SDimitris Papastamos if (!spe_supported()) 62*2ff8fbf3SDimitris Papastamos return; 63*2ff8fbf3SDimitris Papastamos 64281a08ccSDimitris Papastamos /* Drain buffered data */ 65281a08ccSDimitris Papastamos psb_csync(); 66281a08ccSDimitris Papastamos dsbnsh(); 67281a08ccSDimitris Papastamos 68281a08ccSDimitris Papastamos /* Disable profiling buffer */ 69281a08ccSDimitris Papastamos v = read_pmblimitr_el1(); 70281a08ccSDimitris Papastamos v &= ~(1ULL << 0); 71281a08ccSDimitris Papastamos write_pmblimitr_el1(v); 72281a08ccSDimitris Papastamos isb(); 73281a08ccSDimitris Papastamos } 74281a08ccSDimitris Papastamos 75281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg) 76281a08ccSDimitris Papastamos { 77*2ff8fbf3SDimitris Papastamos if (!spe_supported()) 78*2ff8fbf3SDimitris Papastamos return (void *)-1; 79281a08ccSDimitris Papastamos 80281a08ccSDimitris Papastamos /* Drain buffered data */ 81281a08ccSDimitris Papastamos psb_csync(); 82281a08ccSDimitris Papastamos dsbnsh(); 83281a08ccSDimitris Papastamos return 0; 84281a08ccSDimitris Papastamos } 85281a08ccSDimitris Papastamos 86281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 87