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 709d40e0eSAntonio Nino Diaz #include <stdbool.h> 809d40e0eSAntonio Nino Diaz 9281a08ccSDimitris Papastamos #include <arch.h> 10281a08ccSDimitris Papastamos #include <arch_helpers.h> 1109d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub.h> 1209d40e0eSAntonio Nino Diaz #include <lib/extensions/spe.h> 13281a08ccSDimitris Papastamos 1440daecc1SAntonio Nino Diaz static inline void psb_csync(void) 1540daecc1SAntonio Nino Diaz { 16281a08ccSDimitris Papastamos /* 17281a08ccSDimitris Papastamos * The assembler does not yet understand the psb csync mnemonic 18281a08ccSDimitris Papastamos * so use the equivalent hint instruction. 19281a08ccSDimitris Papastamos */ 2040daecc1SAntonio Nino Diaz __asm__ volatile("hint #17"); 2140daecc1SAntonio Nino Diaz } 22281a08ccSDimitris Papastamos 2340daecc1SAntonio Nino Diaz bool spe_supported(void) 24281a08ccSDimitris Papastamos { 25281a08ccSDimitris Papastamos uint64_t features; 26281a08ccSDimitris Papastamos 27281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 28*b8535929SAndre Przywara return (features & ID_AA64DFR0_PMS_MASK) > 0ULL; 292ff8fbf3SDimitris Papastamos } 302ff8fbf3SDimitris Papastamos 3140daecc1SAntonio Nino Diaz void spe_enable(bool el2_unused) 322ff8fbf3SDimitris Papastamos { 33281a08ccSDimitris Papastamos uint64_t v; 34281a08ccSDimitris Papastamos 3540daecc1SAntonio Nino Diaz if (!spe_supported()) 362ff8fbf3SDimitris Papastamos return; 372ff8fbf3SDimitris Papastamos 38281a08ccSDimitris Papastamos if (el2_unused) { 39281a08ccSDimitris Papastamos /* 40281a08ccSDimitris Papastamos * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 41281a08ccSDimitris Papastamos * profiling controls to EL2. 42281a08ccSDimitris Papastamos * 43281a08ccSDimitris Papastamos * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 44281a08ccSDimitris Papastamos * state. Accesses to profiling buffer controls at 45281a08ccSDimitris Papastamos * Non-secure EL1 are not trapped to EL2. 46281a08ccSDimitris Papastamos */ 47281a08ccSDimitris Papastamos v = read_mdcr_el2(); 48281a08ccSDimitris Papastamos v &= ~MDCR_EL2_TPMS; 49281a08ccSDimitris Papastamos v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 50281a08ccSDimitris Papastamos write_mdcr_el2(v); 51281a08ccSDimitris Papastamos } 52281a08ccSDimitris Papastamos 53281a08ccSDimitris Papastamos /* 54281a08ccSDimitris Papastamos * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 55281a08ccSDimitris Papastamos * and disabled in secure state. Accesses to SPE registers at 56281a08ccSDimitris Papastamos * S-EL1 generate trap exceptions to EL3. 57281a08ccSDimitris Papastamos */ 58281a08ccSDimitris Papastamos v = read_mdcr_el3(); 59281a08ccSDimitris Papastamos v |= MDCR_NSPB(MDCR_NSPB_EL1); 60281a08ccSDimitris Papastamos write_mdcr_el3(v); 61281a08ccSDimitris Papastamos } 62281a08ccSDimitris Papastamos 63281a08ccSDimitris Papastamos void spe_disable(void) 64281a08ccSDimitris Papastamos { 65281a08ccSDimitris Papastamos uint64_t v; 66281a08ccSDimitris Papastamos 6740daecc1SAntonio Nino Diaz if (!spe_supported()) 682ff8fbf3SDimitris Papastamos return; 692ff8fbf3SDimitris Papastamos 70281a08ccSDimitris Papastamos /* Drain buffered data */ 71281a08ccSDimitris Papastamos psb_csync(); 72281a08ccSDimitris Papastamos dsbnsh(); 73281a08ccSDimitris Papastamos 74281a08ccSDimitris Papastamos /* Disable profiling buffer */ 75281a08ccSDimitris Papastamos v = read_pmblimitr_el1(); 76281a08ccSDimitris Papastamos v &= ~(1ULL << 0); 77281a08ccSDimitris Papastamos write_pmblimitr_el1(v); 78281a08ccSDimitris Papastamos isb(); 79281a08ccSDimitris Papastamos } 80281a08ccSDimitris Papastamos 81281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg) 82281a08ccSDimitris Papastamos { 8340daecc1SAntonio Nino Diaz if (!spe_supported()) 842ff8fbf3SDimitris Papastamos return (void *)-1; 85281a08ccSDimitris Papastamos 86281a08ccSDimitris Papastamos /* Drain buffered data */ 87281a08ccSDimitris Papastamos psb_csync(); 88281a08ccSDimitris Papastamos dsbnsh(); 8940daecc1SAntonio Nino Diaz 9040daecc1SAntonio Nino Diaz return (void *)0; 91281a08ccSDimitris Papastamos } 92281a08ccSDimitris Papastamos 93281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 94