1281a08ccSDimitris Papastamos /* 2*7fabe1a8SRoberto Vargas * 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> 10*7fabe1a8SRoberto Vargas #include <spe.h> 11281a08ccSDimitris Papastamos 12281a08ccSDimitris Papastamos /* 13281a08ccSDimitris Papastamos * The assembler does not yet understand the psb csync mnemonic 14281a08ccSDimitris Papastamos * so use the equivalent hint instruction. 15281a08ccSDimitris Papastamos */ 16281a08ccSDimitris Papastamos #define psb_csync() asm volatile("hint #17") 17281a08ccSDimitris Papastamos 18281a08ccSDimitris Papastamos void spe_enable(int el2_unused) 19281a08ccSDimitris Papastamos { 20281a08ccSDimitris Papastamos uint64_t features; 21281a08ccSDimitris Papastamos 22281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 23281a08ccSDimitris Papastamos if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 24281a08ccSDimitris Papastamos uint64_t v; 25281a08ccSDimitris Papastamos 26281a08ccSDimitris Papastamos if (el2_unused) { 27281a08ccSDimitris Papastamos /* 28281a08ccSDimitris Papastamos * MDCR_EL2.TPMS (ARM v8.2): Do not trap statistical 29281a08ccSDimitris Papastamos * profiling controls to EL2. 30281a08ccSDimitris Papastamos * 31281a08ccSDimitris Papastamos * MDCR_EL2.E2PB (ARM v8.2): SPE enabled in Non-secure 32281a08ccSDimitris Papastamos * state. Accesses to profiling buffer controls at 33281a08ccSDimitris Papastamos * Non-secure EL1 are not trapped to EL2. 34281a08ccSDimitris Papastamos */ 35281a08ccSDimitris Papastamos v = read_mdcr_el2(); 36281a08ccSDimitris Papastamos v &= ~MDCR_EL2_TPMS; 37281a08ccSDimitris Papastamos v |= MDCR_EL2_E2PB(MDCR_EL2_E2PB_EL1); 38281a08ccSDimitris Papastamos write_mdcr_el2(v); 39281a08ccSDimitris Papastamos } 40281a08ccSDimitris Papastamos 41281a08ccSDimitris Papastamos /* 42281a08ccSDimitris Papastamos * MDCR_EL2.NSPB (ARM v8.2): SPE enabled in Non-secure state 43281a08ccSDimitris Papastamos * and disabled in secure state. Accesses to SPE registers at 44281a08ccSDimitris Papastamos * S-EL1 generate trap exceptions to EL3. 45281a08ccSDimitris Papastamos */ 46281a08ccSDimitris Papastamos v = read_mdcr_el3(); 47281a08ccSDimitris Papastamos v |= MDCR_NSPB(MDCR_NSPB_EL1); 48281a08ccSDimitris Papastamos write_mdcr_el3(v); 49281a08ccSDimitris Papastamos } 50281a08ccSDimitris Papastamos } 51281a08ccSDimitris Papastamos 52281a08ccSDimitris Papastamos void spe_disable(void) 53281a08ccSDimitris Papastamos { 54281a08ccSDimitris Papastamos uint64_t features; 55281a08ccSDimitris Papastamos 56281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 57281a08ccSDimitris Papastamos if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 58281a08ccSDimitris Papastamos uint64_t v; 59281a08ccSDimitris Papastamos 60281a08ccSDimitris Papastamos /* Drain buffered data */ 61281a08ccSDimitris Papastamos psb_csync(); 62281a08ccSDimitris Papastamos dsbnsh(); 63281a08ccSDimitris Papastamos 64281a08ccSDimitris Papastamos /* Disable profiling buffer */ 65281a08ccSDimitris Papastamos v = read_pmblimitr_el1(); 66281a08ccSDimitris Papastamos v &= ~(1ULL << 0); 67281a08ccSDimitris Papastamos write_pmblimitr_el1(v); 68281a08ccSDimitris Papastamos isb(); 69281a08ccSDimitris Papastamos } 70281a08ccSDimitris Papastamos } 71281a08ccSDimitris Papastamos 72281a08ccSDimitris Papastamos static void *spe_drain_buffers_hook(const void *arg) 73281a08ccSDimitris Papastamos { 74281a08ccSDimitris Papastamos uint64_t features; 75281a08ccSDimitris Papastamos 76281a08ccSDimitris Papastamos features = read_id_aa64dfr0_el1() >> ID_AA64DFR0_PMS_SHIFT; 77281a08ccSDimitris Papastamos if ((features & ID_AA64DFR0_PMS_MASK) == 1) { 78281a08ccSDimitris Papastamos /* Drain buffered data */ 79281a08ccSDimitris Papastamos psb_csync(); 80281a08ccSDimitris Papastamos dsbnsh(); 81281a08ccSDimitris Papastamos } 82281a08ccSDimitris Papastamos 83281a08ccSDimitris Papastamos return 0; 84281a08ccSDimitris Papastamos } 85281a08ccSDimitris Papastamos 86281a08ccSDimitris Papastamos SUBSCRIBE_TO_EVENT(cm_entering_secure_world, spe_drain_buffers_hook); 87