arm-trusted-firmware/lib/extensions/pmuv3/aarch64/pmuv3.c
Jayanth Dodderi Chidanand a0674ab081 refactor(cm): remove el1 context when SPMD_SPM_AT_SEL2=1
* Currently, EL1 context is included in cpu_context_t by default
  for all the build configurations.
  As part of the cpu context structure, we hold a copy of EL1, EL2
  system registers, per world per PE. This context structure is
  enormous and will continue to grow bigger with the addition of
  new features incorporating  new registers.

* Ideally, EL3 should save and restore the system registers at its next
  lower exception level, which is EL2 in majority of the configurations.

* This patch aims at optimising the memory allocation in cases, when
  the members from the context structure are unused. So el1 system
  register context must be omitted when lower EL is always x-EL2.

* "CTX_INCLUDE_EL2_REGS" is the internal build flag which gets set,
  when SPD=spmd and SPMD_SPM_AT_SEL2=1 or ENABLE_RME=1.
  It indicates, the system registers at EL2 are context switched for
  the respective build configuration. Here, there is no need  to save
  and restore EL1 system registers, while x-EL2 is enabled.

Henceforth, this patch addresses this issue, by taking out the EL1
context at all possible places, while EL2 (CTX_INCLUDE_EL2_REGS) is
enabled, there by saving memory.

Change-Id: Ifddc497d3c810e22a15b1c227a731bcc133c2f4a
Signed-off-by: Jayanth Dodderi Chidanand <jayanthdodderi.chidanand@arm.com>
2024-08-21 16:35:27 +01:00

173 lines
5.7 KiB
C

/*
* Copyright (c) 2023-2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <arch.h>
#include <arch_features.h>
#include <arch_helpers.h>
#include <lib/extensions/pmuv3.h>
static u_register_t init_mdcr_el2_hpmn(u_register_t mdcr_el2)
{
/*
* Initialize MDCR_EL2.HPMN to its hardware reset value so we don't
* throw anyone off who expects this to be sensible.
*/
mdcr_el2 &= ~MDCR_EL2_HPMN_MASK;
mdcr_el2 |= ((read_pmcr_el0() >> PMCR_EL0_N_SHIFT) & PMCR_EL0_N_MASK);
return mdcr_el2;
}
void pmuv3_enable(cpu_context_t *ctx)
{
#if (CTX_INCLUDE_EL2_REGS && IMAGE_BL31)
u_register_t mdcr_el2_val;
mdcr_el2_val = read_el2_ctx_common(get_el2_sysregs_ctx(ctx), mdcr_el2);
mdcr_el2_val = init_mdcr_el2_hpmn(mdcr_el2_val);
write_el2_ctx_common(get_el2_sysregs_ctx(ctx), mdcr_el2, mdcr_el2_val);
#endif /* (CTX_INCLUDE_EL2_REGS && IMAGE_BL31) */
}
static u_register_t mtpmu_disable_el3(u_register_t mdcr_el3)
{
if (!is_feat_mtpmu_supported()) {
return mdcr_el3;
}
/*
* MDCR_EL3.MTPME = 0
* FEAT_MTPMU is disabled. The Effective value of PMEVTYPER<n>_EL0.MT is
* zero.
*/
mdcr_el3 &= ~MDCR_MTPME_BIT;
return mdcr_el3;
}
void pmuv3_init_el3(void)
{
u_register_t mdcr_el3 = read_mdcr_el3();
/* ---------------------------------------------------------------------
* Initialise MDCR_EL3, setting all fields rather than relying on hw.
* Some fields are architecturally UNKNOWN on reset.
*
* MDCR_EL3.MPMX: Set to zero to not affect event counters (when
* SPME = 0).
*
* MDCR_EL3.MCCD: Set to one so that cycle counting by PMCCNTR_EL0 is
* prohibited in EL3. This bit is RES0 in versions of the
* architecture with FEAT_PMUv3p7 not implemented.
*
* MDCR_EL3.SCCD: Set to one so that cycle counting by PMCCNTR_EL0 is
* prohibited in Secure state. This bit is RES0 in versions of the
* architecture with FEAT_PMUv3p5 not implemented.
*
* MDCR_EL3.SPME: Set to zero so that event counting is prohibited in
* Secure state (and explicitly EL3 with later revisions). If ARMv8.2
* Debug is not implemented this bit does not have any effect on the
* counters unless there is support for the implementation defined
* authentication interface ExternalSecureNoninvasiveDebugEnabled().
*
* The SPME/MPMX combination is a little tricky. Below is a small
* summary if another combination is ever needed:
* SPME | MPMX | secure world | EL3
* -------------------------------------
* 0 | 0 | disabled | disabled
* 1 | 0 | enabled | enabled
* 0 | 1 | enabled | disabled
* 1 | 1 | enabled | disabled only for counters 0 to
* MDCR_EL2.HPMN - 1. Enabled for the rest
*
* MDCR_EL3.TPM: Set to zero so that EL0, EL1, and EL2 System register
* accesses to all Performance Monitors registers do not trap to EL3.
*/
mdcr_el3 = (mdcr_el3 | MDCR_SCCD_BIT | MDCR_MCCD_BIT) &
~(MDCR_MPMX_BIT | MDCR_SPME_BIT | MDCR_TPM_BIT);
mdcr_el3 = mtpmu_disable_el3(mdcr_el3);
write_mdcr_el3(mdcr_el3);
/* ---------------------------------------------------------------------
* Initialise PMCR_EL0 setting all fields rather than relying
* on hw. Some fields are architecturally UNKNOWN on reset.
*
* PMCR_EL0.DP: Set to one so that the cycle counter,
* PMCCNTR_EL0 does not count when event counting is prohibited.
* Necessary on PMUv3 <= p7 where MDCR_EL3.{SCCD,MCCD} are not
* available
*
* PMCR_EL0.X: Set to zero to disable export of events.
*
* PMCR_EL0.C: Set to one to reset PMCCNTR_EL0 to zero.
*
* PMCR_EL0.P: Set to one to reset each event counter PMEVCNTR<n>_EL0 to
* zero.
*
* PMCR_EL0.E: Set to zero to disable cycle and event counters.
* ---------------------------------------------------------------------
*/
write_pmcr_el0((read_pmcr_el0() | PMCR_EL0_DP_BIT | PMCR_EL0_C_BIT |
PMCR_EL0_P_BIT) & ~(PMCR_EL0_X_BIT | PMCR_EL0_E_BIT));
}
static u_register_t mtpmu_disable_el2(u_register_t mdcr_el2)
{
if (!is_feat_mtpmu_supported()) {
return mdcr_el2;
}
/*
* MDCR_EL2.MTPME = 0
* FEAT_MTPMU is disabled. The Effective value of PMEVTYPER<n>_EL0.MT is
* zero.
*/
mdcr_el2 &= ~MDCR_EL2_MTPME;
return mdcr_el2;
}
void pmuv3_init_el2_unused(void)
{
u_register_t mdcr_el2 = read_mdcr_el2();
/*
* Initialise MDCR_EL2, setting all fields rather than
* relying on hw. Some fields are architecturally
* UNKNOWN on reset.
*
* MDCR_EL2.HLP: Set to one so that event counter overflow, that is
* recorded in PMOVSCLR_EL0[0-30], occurs on the increment that changes
* PMEVCNTR<n>_EL0[63] from 1 to 0, when ARMv8.5-PMU is implemented.
* This bit is RES0 in versions of the architecture earlier than
* ARMv8.5, setting it to 1 doesn't have any effect on them.
*
* MDCR_EL2.HCCD: Set to one to prohibit cycle counting at EL2. This bit
* is RES0 in versions of the architecture with FEAT_PMUv3p5 not
* implemented.
*
* MDCR_EL2.HPMD: Set to one so that event counting is
* prohibited at EL2 for counter n < MDCR_EL2.HPMN. This bit is RES0
* in versions of the architecture with FEAT_PMUv3p1 not implemented.
*
* MDCR_EL2.HPME: Set to zero to disable event counters for counters
* n >= MDCR_EL2.HPMN.
*
* MDCR_EL2.TPM: Set to zero so that Non-secure EL0 and
* EL1 accesses to all Performance Monitors registers
* are not trapped to EL2.
*
* MDCR_EL2.TPMCR: Set to zero so that Non-secure EL0
* and EL1 accesses to the PMCR_EL0 or PMCR are not
* trapped to EL2.
*/
mdcr_el2 = (mdcr_el2 | MDCR_EL2_HLP_BIT | MDCR_EL2_HPMD_BIT |
MDCR_EL2_HCCD_BIT) &
~(MDCR_EL2_HPME_BIT | MDCR_EL2_TPM_BIT | MDCR_EL2_TPMCR_BIT);
mdcr_el2 = init_mdcr_el2_hpmn(mdcr_el2);
mdcr_el2 = mtpmu_disable_el2(mdcr_el2);
write_mdcr_el2(mdcr_el2);
}