1281a08ccSDimitris Papastamos /* 22ff8fbf3SDimitris 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> 107fabe1a8SRoberto Vargas #include <spe.h> 11*40daecc1SAntonio Nino Diaz #include <stdbool.h> 12281a08ccSDimitris Papastamos 13*40daecc1SAntonio Nino Diaz static inline void psb_csync(void) 14*40daecc1SAntonio Nino Diaz { 15281a08ccSDimitris Papastamos /* 16281a08ccSDimitris Papastamos * The assembler does not yet understand the psb csync mnemonic 17281a08ccSDimitris Papastamos * so use the equivalent hint instruction. 18281a08ccSDimitris Papastamos */ 19*40daecc1SAntonio Nino Diaz __asm__ volatile("hint #17"); 20*40daecc1SAntonio Nino Diaz } 21281a08ccSDimitris Papastamos 22*40daecc1SAntonio Nino Diaz bool spe_supported(void) 23281a08ccSDimitris Papastamos { 24281a08ccSDimitris Papastamos uint64_t features; 25281a08ccSDimitris Papastamos 26281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 27*40daecc1SAntonio Nino Diaz return (features & ID_AA64DFR0_PMS_MASK) == 1U; 282ff8fbf3SDimitris Papastamos } 292ff8fbf3SDimitris Papastamos 30*40daecc1SAntonio Nino Diaz void spe_enable(bool el2_unused) 312ff8fbf3SDimitris Papastamos { 32281a08ccSDimitris Papastamos uint64_t v; 33281a08ccSDimitris Papastamos 34*40daecc1SAntonio Nino Diaz if (!spe_supported()) 352ff8fbf3SDimitris Papastamos return; 362ff8fbf3SDimitris Papastamos 37281a08ccSDimitris Papastamos if (el2_unused) { 38281a08ccSDimitris Papastamos /* 39281a08ccSDimitris Papastamos * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 40281a08ccSDimitris Papastamos * profiling controls to EL2. 41281a08ccSDimitris Papastamos * 42281a08ccSDimitris Papastamos * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 43281a08ccSDimitris Papastamos * state. Accesses to profiling buffer controls at 44281a08ccSDimitris Papastamos * Non-secure EL1 are not trapped to EL2. 45281a08ccSDimitris Papastamos */ 46281a08ccSDimitris Papastamos v = read_mdcr_el2(); 47281a08ccSDimitris Papastamos v &= ~MDCR_EL2_TPMS; 48281a08ccSDimitris Papastamos v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 49281a08ccSDimitris Papastamos write_mdcr_el2(v); 50281a08ccSDimitris Papastamos } 51281a08ccSDimitris Papastamos 52281a08ccSDimitris Papastamos /* 53281a08ccSDimitris Papastamos * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 54281a08ccSDimitris Papastamos * and disabled in secure state. Accesses to SPE registers at 55281a08ccSDimitris Papastamos * S-EL1 generate trap exceptions to EL3. 56281a08ccSDimitris Papastamos */ 57281a08ccSDimitris Papastamos v = read_mdcr_el3(); 58281a08ccSDimitris Papastamos v |= MDCR_NSPB(MDCR_NSPB_EL1); 59281a08ccSDimitris Papastamos write_mdcr_el3(v); 60281a08ccSDimitris Papastamos } 61281a08ccSDimitris Papastamos 62281a08ccSDimitris Papastamos void spe_disable(void) 63281a08ccSDimitris Papastamos { 64281a08ccSDimitris Papastamos uint64_t v; 65281a08ccSDimitris Papastamos 66*40daecc1SAntonio Nino Diaz if (!spe_supported()) 672ff8fbf3SDimitris Papastamos return; 682ff8fbf3SDimitris Papastamos 69281a08ccSDimitris Papastamos /* Drain buffered data */ 70281a08ccSDimitris Papastamos psb_csync(); 71281a08ccSDimitris Papastamos dsbnsh(); 72281a08ccSDimitris Papastamos 73281a08ccSDimitris Papastamos /* Disable profiling buffer */ 74281a08ccSDimitris Papastamos v = read_pmblimitr_el1(); 75281a08ccSDimitris Papastamos v &= ~(1ULL << 0); 76281a08ccSDimitris Papastamos write_pmblimitr_el1(v); 77281a08ccSDimitris Papastamos isb(); 78281a08ccSDimitris Papastamos } 79281a08ccSDimitris Papastamos 80281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg) 81281a08ccSDimitris Papastamos { 82*40daecc1SAntonio Nino Diaz if (!spe_supported()) 832ff8fbf3SDimitris Papastamos return (void *)-1; 84281a08ccSDimitris Papastamos 85281a08ccSDimitris Papastamos /* Drain buffered data */ 86281a08ccSDimitris Papastamos psb_csync(); 87281a08ccSDimitris Papastamos dsbnsh(); 88*40daecc1SAntonio Nino Diaz 89*40daecc1SAntonio Nino Diaz return (void *)0; 90281a08ccSDimitris Papastamos } 91281a08ccSDimitris Papastamos 92281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 93