1380559c1SDimitris Papastamos /* 2873d4241Sjohpow01 * Copyright (c) 2017-2021, ARM Limited and Contributors. All rights reserved. 3380559c1SDimitris Papastamos * 4380559c1SDimitris Papastamos * SPDX-License-Identifier: BSD-3-Clause 5380559c1SDimitris Papastamos */ 6380559c1SDimitris Papastamos 709d40e0eSAntonio Nino Diaz #include <assert.h> 833b9be6dSChris Kay #include <cdefs.h> 909d40e0eSAntonio Nino Diaz #include <stdbool.h> 1009d40e0eSAntonio Nino Diaz 11380559c1SDimitris Papastamos #include <arch.h> 12873d4241Sjohpow01 #include <arch_features.h> 13380559c1SDimitris Papastamos #include <arch_helpers.h> 14f3ccf036SAlexei Fedorov 1509d40e0eSAntonio Nino Diaz #include <lib/el3_runtime/pubsub_events.h> 1609d40e0eSAntonio Nino Diaz #include <lib/extensions/amu.h> 1709d40e0eSAntonio Nino Diaz #include <lib/extensions/amu_private.h> 18f3ccf036SAlexei Fedorov 1909d40e0eSAntonio Nino Diaz #include <plat/common/platform.h> 20380559c1SDimitris Papastamos 21b6eb3932SDimitris Papastamos static struct amu_ctx amu_ctxs[PLATFORM_CORE_COUNT]; 22b6eb3932SDimitris Papastamos 2333b9be6dSChris Kay static inline __unused uint64_t read_id_aa64pfr0_el1_amu(void) 24380559c1SDimitris Papastamos { 2533b9be6dSChris Kay return (read_id_aa64pfr0_el1() >> ID_AA64PFR0_AMU_SHIFT) & 26873d4241Sjohpow01 ID_AA64PFR0_AMU_MASK; 270767d50eSDimitris Papastamos } 280767d50eSDimitris Papastamos 2933b9be6dSChris Kay static inline __unused uint64_t read_hcr_el2_amvoffen(void) 3033b9be6dSChris Kay { 3133b9be6dSChris Kay return (read_hcr_el2() & HCR_AMVOFFEN_BIT) >> 3233b9be6dSChris Kay HCR_AMVOFFEN_SHIFT; 3333b9be6dSChris Kay } 3433b9be6dSChris Kay 3533b9be6dSChris Kay static inline __unused void write_cptr_el2_tam(uint64_t value) 3633b9be6dSChris Kay { 3733b9be6dSChris Kay write_cptr_el2((read_cptr_el2() & ~CPTR_EL2_TAM_BIT) | 3833b9be6dSChris Kay ((value << CPTR_EL2_TAM_SHIFT) & CPTR_EL2_TAM_BIT)); 3933b9be6dSChris Kay } 4033b9be6dSChris Kay 4133b9be6dSChris Kay static inline __unused void write_cptr_el3_tam(cpu_context_t *ctx, uint64_t tam) 4233b9be6dSChris Kay { 4333b9be6dSChris Kay uint64_t value = read_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3); 4433b9be6dSChris Kay 4533b9be6dSChris Kay value &= ~TAM_BIT; 4633b9be6dSChris Kay value |= (tam << TAM_SHIFT) & TAM_BIT; 4733b9be6dSChris Kay 4833b9be6dSChris Kay write_ctx_reg(get_el3state_ctx(ctx), CTX_CPTR_EL3, value); 4933b9be6dSChris Kay } 5033b9be6dSChris Kay 5133b9be6dSChris Kay static inline __unused void write_hcr_el2_amvoffen(uint64_t value) 5233b9be6dSChris Kay { 5333b9be6dSChris Kay write_hcr_el2((read_hcr_el2() & ~HCR_AMVOFFEN_BIT) | 5433b9be6dSChris Kay ((value << HCR_AMVOFFEN_SHIFT) & HCR_AMVOFFEN_BIT)); 5533b9be6dSChris Kay } 5633b9be6dSChris Kay 5733b9be6dSChris Kay static inline __unused void write_amcr_el0_cg1rz(uint64_t value) 5833b9be6dSChris Kay { 5933b9be6dSChris Kay write_amcr_el0((read_amcr_el0() & ~AMCR_CG1RZ_BIT) | 6033b9be6dSChris Kay ((value << AMCR_CG1RZ_SHIFT) & AMCR_CG1RZ_BIT)); 6133b9be6dSChris Kay } 6233b9be6dSChris Kay 6333b9be6dSChris Kay static inline __unused uint64_t read_amcfgr_el0_ncg(void) 6433b9be6dSChris Kay { 6533b9be6dSChris Kay return (read_amcfgr_el0() >> AMCFGR_EL0_NCG_SHIFT) & 6633b9be6dSChris Kay AMCFGR_EL0_NCG_MASK; 6733b9be6dSChris Kay } 6833b9be6dSChris Kay 69*81e2ff1fSChris Kay static inline uint64_t read_amcgcr_el0_cg0nc(void) 70*81e2ff1fSChris Kay { 71*81e2ff1fSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG0NC_SHIFT) & 72*81e2ff1fSChris Kay AMCGCR_EL0_CG0NC_MASK; 73*81e2ff1fSChris Kay } 74*81e2ff1fSChris Kay 7533b9be6dSChris Kay static inline __unused uint64_t read_amcg1idr_el0_voff(void) 7633b9be6dSChris Kay { 7733b9be6dSChris Kay return (read_amcg1idr_el0() >> AMCG1IDR_VOFF_SHIFT) & 7833b9be6dSChris Kay AMCG1IDR_VOFF_MASK; 7933b9be6dSChris Kay } 8033b9be6dSChris Kay 8133b9be6dSChris Kay static inline __unused uint64_t read_amcgcr_el0_cg1nc(void) 8233b9be6dSChris Kay { 8333b9be6dSChris Kay return (read_amcgcr_el0() >> AMCGCR_EL0_CG1NC_SHIFT) & 8433b9be6dSChris Kay AMCGCR_EL0_CG1NC_MASK; 8533b9be6dSChris Kay } 8633b9be6dSChris Kay 8733b9be6dSChris Kay static inline __unused uint64_t read_amcntenset0_el0_px(void) 8833b9be6dSChris Kay { 8933b9be6dSChris Kay return (read_amcntenset0_el0() >> AMCNTENSET0_EL0_Pn_SHIFT) & 9033b9be6dSChris Kay AMCNTENSET0_EL0_Pn_MASK; 9133b9be6dSChris Kay } 9233b9be6dSChris Kay 9333b9be6dSChris Kay static inline __unused uint64_t read_amcntenset1_el0_px(void) 9433b9be6dSChris Kay { 9533b9be6dSChris Kay return (read_amcntenset1_el0() >> AMCNTENSET1_EL0_Pn_SHIFT) & 9633b9be6dSChris Kay AMCNTENSET1_EL0_Pn_MASK; 9733b9be6dSChris Kay } 9833b9be6dSChris Kay 9933b9be6dSChris Kay static inline __unused void write_amcntenset0_el0_px(uint64_t px) 10033b9be6dSChris Kay { 10133b9be6dSChris Kay uint64_t value = read_amcntenset0_el0(); 10233b9be6dSChris Kay 10333b9be6dSChris Kay value &= ~AMCNTENSET0_EL0_Pn_MASK; 10433b9be6dSChris Kay value |= (px << AMCNTENSET0_EL0_Pn_SHIFT) & AMCNTENSET0_EL0_Pn_MASK; 10533b9be6dSChris Kay 10633b9be6dSChris Kay write_amcntenset0_el0(value); 10733b9be6dSChris Kay } 10833b9be6dSChris Kay 10933b9be6dSChris Kay static inline __unused void write_amcntenset1_el0_px(uint64_t px) 11033b9be6dSChris Kay { 11133b9be6dSChris Kay uint64_t value = read_amcntenset1_el0(); 11233b9be6dSChris Kay 11333b9be6dSChris Kay value &= ~AMCNTENSET1_EL0_Pn_MASK; 11433b9be6dSChris Kay value |= (px << AMCNTENSET1_EL0_Pn_SHIFT) & AMCNTENSET1_EL0_Pn_MASK; 11533b9be6dSChris Kay 11633b9be6dSChris Kay write_amcntenset1_el0(value); 11733b9be6dSChris Kay } 11833b9be6dSChris Kay 11933b9be6dSChris Kay static inline __unused void write_amcntenclr0_el0_px(uint64_t px) 12033b9be6dSChris Kay { 12133b9be6dSChris Kay uint64_t value = read_amcntenclr0_el0(); 12233b9be6dSChris Kay 12333b9be6dSChris Kay value &= ~AMCNTENCLR0_EL0_Pn_MASK; 12433b9be6dSChris Kay value |= (px << AMCNTENCLR0_EL0_Pn_SHIFT) & AMCNTENCLR0_EL0_Pn_MASK; 12533b9be6dSChris Kay 12633b9be6dSChris Kay write_amcntenclr0_el0(value); 12733b9be6dSChris Kay } 12833b9be6dSChris Kay 12933b9be6dSChris Kay static inline __unused void write_amcntenclr1_el0_px(uint64_t px) 13033b9be6dSChris Kay { 13133b9be6dSChris Kay uint64_t value = read_amcntenclr1_el0(); 13233b9be6dSChris Kay 13333b9be6dSChris Kay value &= ~AMCNTENCLR1_EL0_Pn_MASK; 13433b9be6dSChris Kay value |= (px << AMCNTENCLR1_EL0_Pn_SHIFT) & AMCNTENCLR1_EL0_Pn_MASK; 13533b9be6dSChris Kay 13633b9be6dSChris Kay write_amcntenclr1_el0(value); 13733b9be6dSChris Kay } 13833b9be6dSChris Kay 13933b9be6dSChris Kay static bool amu_supported(void) 14033b9be6dSChris Kay { 14133b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1; 14233b9be6dSChris Kay } 14333b9be6dSChris Kay 14433b9be6dSChris Kay static bool amu_v1p1_supported(void) 14533b9be6dSChris Kay { 14633b9be6dSChris Kay return read_id_aa64pfr0_el1_amu() >= ID_AA64PFR0_AMU_V1P1; 14733b9be6dSChris Kay } 14833b9be6dSChris Kay 14933b9be6dSChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 150b4b726eaSChris Kay static bool amu_group1_supported(void) 151f3ccf036SAlexei Fedorov { 15233b9be6dSChris Kay return read_amcfgr_el0_ncg() > 0U; 153f3ccf036SAlexei Fedorov } 154f3ccf036SAlexei Fedorov #endif 155f3ccf036SAlexei Fedorov 1560767d50eSDimitris Papastamos /* 1570767d50eSDimitris Papastamos * Enable counters. This function is meant to be invoked 1580767d50eSDimitris Papastamos * by the context management library before exiting from EL3. 1590767d50eSDimitris Papastamos */ 16068ac5ed0SArunachalam Ganapathy void amu_enable(bool el2_unused, cpu_context_t *ctx) 1610767d50eSDimitris Papastamos { 16233b9be6dSChris Kay if (!amu_supported()) { 1630767d50eSDimitris Papastamos return; 164f3ccf036SAlexei Fedorov } 165f3ccf036SAlexei Fedorov 1661fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 1671fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 168f3ccf036SAlexei Fedorov /* Check and set presence of group 1 counters */ 169f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 170f3ccf036SAlexei Fedorov ERROR("AMU Counter Group 1 is not implemented\n"); 171f3ccf036SAlexei Fedorov panic(); 172f3ccf036SAlexei Fedorov } 173f3ccf036SAlexei Fedorov 174f3ccf036SAlexei Fedorov /* Check number of group 1 counters */ 17533b9be6dSChris Kay uint64_t cnt_num = read_amcgcr_el0_cg1nc(); 1761fd685a7SChris Kay 177f3ccf036SAlexei Fedorov VERBOSE("%s%llu. %s%u\n", 178f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 179f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 180f3ccf036SAlexei Fedorov 181f3ccf036SAlexei Fedorov if (cnt_num < AMU_GROUP1_NR_COUNTERS) { 182f3ccf036SAlexei Fedorov ERROR("%s%llu is less than %s%u\n", 183f3ccf036SAlexei Fedorov "Number of AMU Group 1 Counters ", cnt_num, 184f3ccf036SAlexei Fedorov "Requested number ", AMU_GROUP1_NR_COUNTERS); 185f3ccf036SAlexei Fedorov panic(); 186f3ccf036SAlexei Fedorov } 1871fd685a7SChris Kay } 188f3ccf036SAlexei Fedorov #endif 1890767d50eSDimitris Papastamos 190380559c1SDimitris Papastamos if (el2_unused) { 191380559c1SDimitris Papastamos /* 192380559c1SDimitris Papastamos * CPTR_EL2.TAM: Set to zero so any accesses to 193380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL2. 194380559c1SDimitris Papastamos */ 19533b9be6dSChris Kay write_cptr_el2_tam(0U); 196380559c1SDimitris Papastamos } 197380559c1SDimitris Papastamos 198380559c1SDimitris Papastamos /* 19968ac5ed0SArunachalam Ganapathy * Retrieve and update the CPTR_EL3 value from the context mentioned 20068ac5ed0SArunachalam Ganapathy * in 'ctx'. Set CPTR_EL3.TAM to zero so that any accesses to 201380559c1SDimitris Papastamos * the Activity Monitor registers do not trap to EL3. 202380559c1SDimitris Papastamos */ 20333b9be6dSChris Kay write_cptr_el3_tam(ctx, 0U); 204380559c1SDimitris Papastamos 205380559c1SDimitris Papastamos /* Enable group 0 counters */ 206*81e2ff1fSChris Kay write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 207f3ccf036SAlexei Fedorov 2081fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 2091fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 21059902b7cSDimitris Papastamos /* Enable group 1 counters */ 21133b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 2121fd685a7SChris Kay } 213f3ccf036SAlexei Fedorov #endif 214873d4241Sjohpow01 215873d4241Sjohpow01 /* Initialize FEAT_AMUv1p1 features if present. */ 21633b9be6dSChris Kay if (!amu_v1p1_supported()) { 217873d4241Sjohpow01 return; 218873d4241Sjohpow01 } 219873d4241Sjohpow01 220873d4241Sjohpow01 if (el2_unused) { 221873d4241Sjohpow01 /* Make sure virtual offsets are disabled if EL2 not used. */ 22233b9be6dSChris Kay write_hcr_el2_amvoffen(0U); 223873d4241Sjohpow01 } 224873d4241Sjohpow01 225873d4241Sjohpow01 #if AMU_RESTRICT_COUNTERS 226873d4241Sjohpow01 /* 227873d4241Sjohpow01 * FEAT_AMUv1p1 adds a register field to restrict access to group 1 228873d4241Sjohpow01 * counters at all but the highest implemented EL. This is controlled 229873d4241Sjohpow01 * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system 230873d4241Sjohpow01 * register reads at lower ELs return zero. Reads from the memory 231873d4241Sjohpow01 * mapped view are unaffected. 232873d4241Sjohpow01 */ 233873d4241Sjohpow01 VERBOSE("AMU group 1 counter access restricted.\n"); 23433b9be6dSChris Kay write_amcr_el0_cg1rz(1U); 235873d4241Sjohpow01 #else 23633b9be6dSChris Kay write_amcr_el0_cg1rz(0U); 237873d4241Sjohpow01 #endif 238380559c1SDimitris Papastamos } 2390767d50eSDimitris Papastamos 2400767d50eSDimitris Papastamos /* Read the group 0 counter identified by the given `idx`. */ 241b4b726eaSChris Kay static uint64_t amu_group0_cnt_read(unsigned int idx) 2420767d50eSDimitris Papastamos { 24333b9be6dSChris Kay assert(amu_supported()); 244*81e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 2450767d50eSDimitris Papastamos 2460767d50eSDimitris Papastamos return amu_group0_cnt_read_internal(idx); 2470767d50eSDimitris Papastamos } 2480767d50eSDimitris Papastamos 249f3ccf036SAlexei Fedorov /* Write the group 0 counter identified by the given `idx` with `val` */ 250b4b726eaSChris Kay static void amu_group0_cnt_write(unsigned int idx, uint64_t val) 2510767d50eSDimitris Papastamos { 25233b9be6dSChris Kay assert(amu_supported()); 253*81e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 2540767d50eSDimitris Papastamos 2550767d50eSDimitris Papastamos amu_group0_cnt_write_internal(idx, val); 2560767d50eSDimitris Papastamos isb(); 2570767d50eSDimitris Papastamos } 2580767d50eSDimitris Papastamos 259873d4241Sjohpow01 /* 260873d4241Sjohpow01 * Read the group 0 offset register for a given index. Index must be 0, 2, 261873d4241Sjohpow01 * or 3, the register for 1 does not exist. 262873d4241Sjohpow01 * 263873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 264873d4241Sjohpow01 */ 265b4b726eaSChris Kay static uint64_t amu_group0_voffset_read(unsigned int idx) 266873d4241Sjohpow01 { 26733b9be6dSChris Kay assert(amu_v1p1_supported()); 268*81e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 269873d4241Sjohpow01 assert(idx != 1U); 270873d4241Sjohpow01 271873d4241Sjohpow01 return amu_group0_voffset_read_internal(idx); 272873d4241Sjohpow01 } 273873d4241Sjohpow01 274873d4241Sjohpow01 /* 275873d4241Sjohpow01 * Write the group 0 offset register for a given index. Index must be 0, 2, or 276873d4241Sjohpow01 * 3, the register for 1 does not exist. 277873d4241Sjohpow01 * 278873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 279873d4241Sjohpow01 */ 280b4b726eaSChris Kay static void amu_group0_voffset_write(unsigned int idx, uint64_t val) 281873d4241Sjohpow01 { 28233b9be6dSChris Kay assert(amu_v1p1_supported()); 283*81e2ff1fSChris Kay assert(idx < read_amcgcr_el0_cg0nc()); 284873d4241Sjohpow01 assert(idx != 1U); 285873d4241Sjohpow01 286873d4241Sjohpow01 amu_group0_voffset_write_internal(idx, val); 287873d4241Sjohpow01 isb(); 288873d4241Sjohpow01 } 289873d4241Sjohpow01 2901fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 291f3ccf036SAlexei Fedorov /* Read the group 1 counter identified by the given `idx` */ 292b4b726eaSChris Kay static uint64_t amu_group1_cnt_read(unsigned int idx) 2930767d50eSDimitris Papastamos { 29433b9be6dSChris Kay assert(amu_supported()); 295f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 296f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 2970767d50eSDimitris Papastamos 2980767d50eSDimitris Papastamos return amu_group1_cnt_read_internal(idx); 2990767d50eSDimitris Papastamos } 3000767d50eSDimitris Papastamos 301f3ccf036SAlexei Fedorov /* Write the group 1 counter identified by the given `idx` with `val` */ 302b4b726eaSChris Kay static void amu_group1_cnt_write(unsigned int idx, uint64_t val) 3030767d50eSDimitris Papastamos { 30433b9be6dSChris Kay assert(amu_supported()); 305f3ccf036SAlexei Fedorov assert(amu_group1_supported()); 306f3ccf036SAlexei Fedorov assert(idx < AMU_GROUP1_NR_COUNTERS); 3070767d50eSDimitris Papastamos 3080767d50eSDimitris Papastamos amu_group1_cnt_write_internal(idx, val); 3090767d50eSDimitris Papastamos isb(); 3100767d50eSDimitris Papastamos } 3110767d50eSDimitris Papastamos 3120767d50eSDimitris Papastamos /* 313873d4241Sjohpow01 * Read the group 1 offset register for a given index. 314873d4241Sjohpow01 * 315873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 316873d4241Sjohpow01 */ 317b4b726eaSChris Kay static uint64_t amu_group1_voffset_read(unsigned int idx) 318873d4241Sjohpow01 { 31933b9be6dSChris Kay assert(amu_v1p1_supported()); 320873d4241Sjohpow01 assert(amu_group1_supported()); 321873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 32233b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 323873d4241Sjohpow01 324873d4241Sjohpow01 return amu_group1_voffset_read_internal(idx); 325873d4241Sjohpow01 } 326873d4241Sjohpow01 327873d4241Sjohpow01 /* 328873d4241Sjohpow01 * Write the group 1 offset register for a given index. 329873d4241Sjohpow01 * 330873d4241Sjohpow01 * Using this function requires FEAT_AMUv1p1 support. 331873d4241Sjohpow01 */ 332b4b726eaSChris Kay static void amu_group1_voffset_write(unsigned int idx, uint64_t val) 333873d4241Sjohpow01 { 33433b9be6dSChris Kay assert(amu_v1p1_supported()); 335873d4241Sjohpow01 assert(amu_group1_supported()); 336873d4241Sjohpow01 assert(idx < AMU_GROUP1_NR_COUNTERS); 33733b9be6dSChris Kay assert((read_amcg1idr_el0_voff() & (UINT64_C(1) << idx)) != 0U); 338873d4241Sjohpow01 339873d4241Sjohpow01 amu_group1_voffset_write_internal(idx, val); 340873d4241Sjohpow01 isb(); 341873d4241Sjohpow01 } 3421fd685a7SChris Kay #endif 343b6eb3932SDimitris Papastamos 344b6eb3932SDimitris Papastamos static void *amu_context_save(const void *arg) 345b6eb3932SDimitris Papastamos { 346b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 347f3ccf036SAlexei Fedorov unsigned int i; 348b6eb3932SDimitris Papastamos 34933b9be6dSChris Kay if (!amu_supported()) { 350b6eb3932SDimitris Papastamos return (void *)-1; 351f3ccf036SAlexei Fedorov } 352b6eb3932SDimitris Papastamos 3531fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 3541fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 355f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 356f3ccf036SAlexei Fedorov return (void *)-1; 357f3ccf036SAlexei Fedorov } 3581fd685a7SChris Kay } 359f3ccf036SAlexei Fedorov #endif 3601fd685a7SChris Kay 361b6eb3932SDimitris Papastamos /* Assert that group 0/1 counter configuration is what we expect */ 362*81e2ff1fSChris Kay assert(read_amcntenset0_el0_px() == 363*81e2ff1fSChris Kay ((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U)); 364b6eb3932SDimitris Papastamos 3651fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 3661fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 36733b9be6dSChris Kay assert(read_amcntenset1_el0_px() == AMU_GROUP1_COUNTERS_MASK); 3681fd685a7SChris Kay } 369f3ccf036SAlexei Fedorov #endif 3701fd685a7SChris Kay 371b6eb3932SDimitris Papastamos /* 372b6eb3932SDimitris Papastamos * Disable group 0/1 counters to avoid other observers like SCP sampling 373b6eb3932SDimitris Papastamos * counter values from the future via the memory mapped view. 374b6eb3932SDimitris Papastamos */ 375*81e2ff1fSChris Kay write_amcntenclr0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 376f3ccf036SAlexei Fedorov 3771fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 3781fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 37933b9be6dSChris Kay write_amcntenclr1_el0_px(AMU_GROUP1_COUNTERS_MASK); 3801fd685a7SChris Kay } 381f3ccf036SAlexei Fedorov #endif 3821fd685a7SChris Kay 383b6eb3932SDimitris Papastamos isb(); 384b6eb3932SDimitris Papastamos 385f3ccf036SAlexei Fedorov /* Save all group 0 counters */ 386*81e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) { 387b6eb3932SDimitris Papastamos ctx->group0_cnts[i] = amu_group0_cnt_read(i); 388f3ccf036SAlexei Fedorov } 389b6eb3932SDimitris Papastamos 390873d4241Sjohpow01 /* Save group 0 virtual offsets if supported and enabled. */ 39133b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 392873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 393873d4241Sjohpow01 ctx->group0_voffsets[0U] = amu_group0_voffset_read(0U); 394873d4241Sjohpow01 ctx->group0_voffsets[1U] = amu_group0_voffset_read(2U); 395873d4241Sjohpow01 ctx->group0_voffsets[2U] = amu_group0_voffset_read(3U); 396873d4241Sjohpow01 } 397873d4241Sjohpow01 3981fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 3991fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 400b6eb3932SDimitris Papastamos /* Save group 1 counters */ 401f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 402873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 403b6eb3932SDimitris Papastamos ctx->group1_cnts[i] = amu_group1_cnt_read(i); 404f3ccf036SAlexei Fedorov } 405f3ccf036SAlexei Fedorov } 406873d4241Sjohpow01 407873d4241Sjohpow01 /* Save group 1 virtual offsets if supported and enabled. */ 40833b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 40933b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 41033b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 411873d4241Sjohpow01 412873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 413873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 414873d4241Sjohpow01 ctx->group1_voffsets[i] = 415873d4241Sjohpow01 amu_group1_voffset_read(i); 416873d4241Sjohpow01 } 417873d4241Sjohpow01 } 418873d4241Sjohpow01 } 4191fd685a7SChris Kay } 420f3ccf036SAlexei Fedorov #endif 4211fd685a7SChris Kay 42240daecc1SAntonio Nino Diaz return (void *)0; 423b6eb3932SDimitris Papastamos } 424b6eb3932SDimitris Papastamos 425b6eb3932SDimitris Papastamos static void *amu_context_restore(const void *arg) 426b6eb3932SDimitris Papastamos { 427b6eb3932SDimitris Papastamos struct amu_ctx *ctx = &amu_ctxs[plat_my_core_pos()]; 428f3ccf036SAlexei Fedorov unsigned int i; 429b6eb3932SDimitris Papastamos 43033b9be6dSChris Kay if (!amu_supported()) { 431b6eb3932SDimitris Papastamos return (void *)-1; 432f3ccf036SAlexei Fedorov } 433b6eb3932SDimitris Papastamos 4341fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 4351fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 436f3ccf036SAlexei Fedorov if (!amu_group1_supported()) { 437f3ccf036SAlexei Fedorov return (void *)-1; 438f3ccf036SAlexei Fedorov } 4391fd685a7SChris Kay } 440f3ccf036SAlexei Fedorov #endif 4411fd685a7SChris Kay 442b6eb3932SDimitris Papastamos /* Counters were disabled in `amu_context_save()` */ 44333b9be6dSChris Kay assert(read_amcntenset0_el0_px() == 0U); 444b6eb3932SDimitris Papastamos 4451fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 4461fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 44733b9be6dSChris Kay assert(read_amcntenset1_el0_px() == 0U); 4481fd685a7SChris Kay } 449f3ccf036SAlexei Fedorov #endif 450b6eb3932SDimitris Papastamos 451f3ccf036SAlexei Fedorov /* Restore all group 0 counters */ 452*81e2ff1fSChris Kay for (i = 0U; i < read_amcgcr_el0_cg0nc(); i++) { 453b6eb3932SDimitris Papastamos amu_group0_cnt_write(i, ctx->group0_cnts[i]); 454f3ccf036SAlexei Fedorov } 455b6eb3932SDimitris Papastamos 456873d4241Sjohpow01 /* Restore group 0 virtual offsets if supported and enabled. */ 45733b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 458873d4241Sjohpow01 /* Not using a loop because count is fixed and index 1 DNE. */ 459873d4241Sjohpow01 amu_group0_voffset_write(0U, ctx->group0_voffsets[0U]); 460873d4241Sjohpow01 amu_group0_voffset_write(2U, ctx->group0_voffsets[1U]); 461873d4241Sjohpow01 amu_group0_voffset_write(3U, ctx->group0_voffsets[2U]); 462873d4241Sjohpow01 } 463873d4241Sjohpow01 464f3ccf036SAlexei Fedorov /* Restore group 0 counter configuration */ 465*81e2ff1fSChris Kay write_amcntenset0_el0_px((UINT64_C(1) << read_amcgcr_el0_cg0nc()) - 1U); 466f3ccf036SAlexei Fedorov 4671fd685a7SChris Kay #if ENABLE_AMU_AUXILIARY_COUNTERS 4681fd685a7SChris Kay if (AMU_GROUP1_NR_COUNTERS > 0U) { 469f3ccf036SAlexei Fedorov /* Restore group 1 counters */ 470f3ccf036SAlexei Fedorov for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 471873d4241Sjohpow01 if ((AMU_GROUP1_COUNTERS_MASK & (1UL << i)) != 0U) { 472f3ccf036SAlexei Fedorov amu_group1_cnt_write(i, ctx->group1_cnts[i]); 473f3ccf036SAlexei Fedorov } 474f3ccf036SAlexei Fedorov } 475f3ccf036SAlexei Fedorov 476873d4241Sjohpow01 /* Restore group 1 virtual offsets if supported and enabled. */ 47733b9be6dSChris Kay if (amu_v1p1_supported() && (read_hcr_el2_amvoffen() != 0U)) { 47833b9be6dSChris Kay uint64_t amcg1idr = read_amcg1idr_el0_voff() & 47933b9be6dSChris Kay AMU_GROUP1_COUNTERS_MASK; 480873d4241Sjohpow01 481873d4241Sjohpow01 for (i = 0U; i < AMU_GROUP1_NR_COUNTERS; i++) { 482873d4241Sjohpow01 if (((amcg1idr >> i) & 1ULL) != 0ULL) { 483873d4241Sjohpow01 amu_group1_voffset_write(i, 484873d4241Sjohpow01 ctx->group1_voffsets[i]); 485873d4241Sjohpow01 } 486873d4241Sjohpow01 } 487873d4241Sjohpow01 } 488873d4241Sjohpow01 489f3ccf036SAlexei Fedorov /* Restore group 1 counter configuration */ 49033b9be6dSChris Kay write_amcntenset1_el0_px(AMU_GROUP1_COUNTERS_MASK); 4911fd685a7SChris Kay } 492f3ccf036SAlexei Fedorov #endif 493b6eb3932SDimitris Papastamos 49440daecc1SAntonio Nino Diaz return (void *)0; 495b6eb3932SDimitris Papastamos } 496b6eb3932SDimitris Papastamos 497b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_start, amu_context_save); 498b6eb3932SDimitris Papastamos SUBSCRIBE_TO_EVENT(psci_suspend_pwrdown_finish, amu_context_restore); 499