Merge changes from topic "ar/pmuSaveRestore" into integration

* changes:
  feat(tc): add save/restore DSU PMU register support
  feat(dsu): save/restore DSU PMU register
  feat(plat): add platform API that gets cluster ID
This commit is contained in:
Manish Pandey 2024-05-10 11:46:42 +02:00 committed by TrustedFirmware Code Review
commit b38b37ba06
13 changed files with 285 additions and 7 deletions

View file

@ -1207,6 +1207,7 @@ $(eval $(call assert_booleans,\
INIT_UNUSED_NS_EL2 \ INIT_UNUSED_NS_EL2 \
PLATFORM_REPORT_CTX_MEM_USE \ PLATFORM_REPORT_CTX_MEM_USE \
EARLY_CONSOLE \ EARLY_CONSOLE \
PRESERVE_DSU_PMU_REGS \
))) )))
# Numeric_Flags # Numeric_Flags
@ -1405,6 +1406,7 @@ $(eval $(call add_defines,\
INIT_UNUSED_NS_EL2 \ INIT_UNUSED_NS_EL2 \
PLATFORM_REPORT_CTX_MEM_USE \ PLATFORM_REPORT_CTX_MEM_USE \
EARLY_CONSOLE \ EARLY_CONSOLE \
PRESERVE_DSU_PMU_REGS \
))) )))
ifeq (${PLATFORM_REPORT_CTX_MEM_USE}, 1) ifeq (${PLATFORM_REPORT_CTX_MEM_USE}, 1)

View file

@ -768,6 +768,11 @@ Common build options
``EL3_PAYLOAD_BASE``. If both are defined, ``EL3_PAYLOAD_BASE`` has priority ``EL3_PAYLOAD_BASE``. If both are defined, ``EL3_PAYLOAD_BASE`` has priority
over ``PRELOADED_BL33_BASE``. over ``PRELOADED_BL33_BASE``.
- ``PRESERVE_DSU_PMU_REGS``: This options when enabled allows the platform to
save/restore the DynamIQ Shared Unit's(DSU) Performance Monitoring Unit(PMU)
registers when the cluster goes through a power cycle. This is disabled by
default and platforms that require this feature have to enable them.
- ``PROGRAMMABLE_RESET_ADDRESS``: This option indicates whether the reset - ``PROGRAMMABLE_RESET_ADDRESS``: This option indicates whether the reset
vector address can be programmed or is fixed on the platform. It can take vector address can be programmed or is fixed on the platform. It can take
either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a either 0 (fixed) or 1 (programmable). Default is 0. If the platform has a

135
drivers/arm/css/dsu/dsu.c Normal file
View file

@ -0,0 +1,135 @@
/*
* Copyright (c) 2024, Arm Limited. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#include <assert.h>
#include <arch.h>
#include <arch_helpers.h>
#include <common/bl_common.h>
#include <common/debug.h>
#include <drivers/arm/css/dsu.h>
#include <plat/arm/common/plat_arm.h>
#include <plat/common/platform.h>
/*
* Context structure that saves the state of DSU PMU registers
*/
cluster_pmu_state_t cluster_pmu_context[PLAT_ARM_CLUSTER_COUNT];
/****************************************************************************
* This function, save_dsu_pmu_state, is designed to save the
* current state of the Performance Monitoring Unit (PMU) for a cluster.
*
* The function performs the following operations:
* 1. Saves the current values of several PMU registers
* (CLUSTERPMCR_EL1, CLUSTERPMCNTENSET_EL1, CLUSTERPMCCNTR_EL1,
* CLUSTERPMOVSSET_EL1, and CLUSTERPMSELR_EL1) into the cluster_pmu_state
* structure.
*
* 2. Disables the PMU event counting by
* clearing the E bit in the clusterpmcr_el1 register.
*
* 3. Iterates over the available PMU counters as
* determined by the read_cluster_eventctr_num() function.
* For each counter, it:
* a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
* b. Reads the current counter value (event count) and
* the event type being counted from CLUSTERPMXEVCNTR_EL1 and
* CLUSTERPMXEVTYPER_EL1 registers, respectively.
*
* This function is useful for preserving the DynamIQ Shared Unit's (DSU)
* PMU registers over a power cycle.
***************************************************************************/
void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
{
unsigned int idx = 0U;
unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
assert(cluster_pmu_state != 0);
save_pmu_reg(cluster_pmu_state, clusterpmcr);
write_clusterpmcr(cluster_pmu_state->clusterpmcr &
~(CLUSTERPMCR_E_BIT));
save_pmu_reg(cluster_pmu_state, clusterpmcntenset);
save_pmu_reg(cluster_pmu_state, clusterpmccntr);
save_pmu_reg(cluster_pmu_state, clusterpmovsset);
save_pmu_reg(cluster_pmu_state, clusterpmselr);
for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
write_clusterpmselr(idx);
cluster_pmu_state->counter_val[idx] = read_clusterpmxevcntr();
cluster_pmu_state->counter_type[idx] = read_clusterpmxevtyper();
}
}
void cluster_off_dsu_pmu_context_save(void)
{
unsigned int cluster_pos;
cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
save_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
}
/*****************************************************************************
* This function, restore_dsu_pmu_state, restores the state of the
* Performance Monitoring Unit (PMU) from a previously saved state.
*
* The function performs the following operations:
* 1. Restores the CLUSTERPMCR_EL1 register with the
* saved value from the cluster_pmu_state structure.
* 2. Iterates over the available PMU counters as determined
* by the read_cluster_eventctr_num() function. For each counter, it:
* a. Selects the counter by writing its index to CLUSTERPMSELR_EL1.
* b. Restores the counter value (event count) and the event type to
* CLUSTERPMXEVCNTR_EL1 and CLUSTERPMXEVTYPER_EL1 registers, respectively
* 3. Restores several other PMU registers (CLUSTERPMSELR_EL1,
* CLUSTERPMOVSCLR_EL1, CLUSTERPMOVSSET_EL1, CLUSTERPMCCNTR_EL1,
* and CLUSTERPMCNTENSET_EL1) with their saved values.
*
*****************************************************************************/
void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_state)
{
unsigned int idx = 0U;
unsigned int cluster_eventctr_num = read_cluster_eventctr_num();
assert(cluster_pmu_state != 0);
for (idx = 0U ; idx < cluster_eventctr_num ; idx++) {
write_clusterpmselr(idx);
write_clusterpmxevcntr(cluster_pmu_state->counter_val[idx]);
write_clusterpmxevtyper(cluster_pmu_state->counter_type[idx]);
}
restore_pmu_reg(cluster_pmu_state, clusterpmselr);
write_clusterpmovsclr(~(uint32_t)cluster_pmu_state->clusterpmovsset);
restore_pmu_reg(cluster_pmu_state, clusterpmovsset);
restore_pmu_reg(cluster_pmu_state, clusterpmccntr);
restore_pmu_reg(cluster_pmu_state, clusterpmcntenset);
write_clusterpmcr(cluster_pmu_state->clusterpmcr);
}
void cluster_on_dsu_pmu_context_restore(void)
{
unsigned int cluster_pos;
cluster_pos = (unsigned int) plat_cluster_id_by_mpidr(read_mpidr_el1());
restore_dsu_pmu_state(&cluster_pmu_context[cluster_pos]);
}

View file

@ -795,7 +795,21 @@
/******************************************************************************* /*******************************************************************************
* Definitions for DynamicIQ Shared Unit registers * Definitions for DynamicIQ Shared Unit registers
******************************************************************************/ ******************************************************************************/
#define CLUSTERPWRDN p15, 0, c15, c3, 6 #define CLUSTERPWRDN p15, 0, c15, c3, 6
#define CLUSTERPMCR p15, 0, c15, c5, 0
#define CLUSTERPMCNTENSET p15, 0, c15, c5, 1
#define CLUSTERPMCCNTR p15, 0, c15, c6, 0
#define CLUSTERPMOVSSET p15, 0, c15, c5, 3
#define CLUSTERPMOVSCLR p15, 0, c15, c5, 4
#define CLUSTERPMSELR p15, 0, c15, c5, 5
#define CLUSTERPMXEVTYPER p15, 0, c15, c6, 1
#define CLUSTERPMXEVCNTR p15, 0, c15, c6, 2
/* CLUSTERPMCR register definitions */
#define CLUSTERPMCR_E_BIT BIT(0)
#define CLUSTERPMCR_N_SHIFT U(11)
#define CLUSTERPMCR_N_MASK U(0x1f)
/* CLUSTERPWRDN register definitions */ /* CLUSTERPWRDN register definitions */
#define DSU_CLUSTER_PWR_OFF 0 #define DSU_CLUSTER_PWR_OFF 0

View file

@ -1,5 +1,5 @@
/* /*
* Copyright (c) 2016-2021, ARM Limited and Contributors. All rights reserved. * Copyright (c) 2016-2024, ARM Limited and Contributors. All rights reserved.
* Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved. * Portions copyright (c) 2021-2022, ProvenRun S.A.S. All rights reserved.
* *
* SPDX-License-Identifier: BSD-3-Clause * SPDX-License-Identifier: BSD-3-Clause
@ -354,6 +354,14 @@ DEFINE_DCOP_PARAM_FUNC(cvac, DCCMVAC)
* DynamIQ Shared Unit power management * DynamIQ Shared Unit power management
*/ */
DEFINE_COPROCR_RW_FUNCS(clusterpwrdn, CLUSTERPWRDN) DEFINE_COPROCR_RW_FUNCS(clusterpwrdn, CLUSTERPWRDN)
DEFINE_COPROCR_RW_FUNCS(clusterpmcr, CLUSTERPMCR)
DEFINE_COPROCR_RW_FUNCS(clusterpmcntenset, CLUSTERPMCNTENSET)
DEFINE_COPROCR_RW_FUNCS(clusterpmccntr, CLUSTERPMCCNTR)
DEFINE_COPROCR_RW_FUNCS(clusterpmovsset, CLUSTERPMOVSSET)
DEFINE_COPROCR_RW_FUNCS(clusterpmovsclr, CLUSTERPMOVSCLR)
DEFINE_COPROCR_RW_FUNCS(clusterpmselr, CLUSTERPMSELR)
DEFINE_COPROCR_RW_FUNCS(clusterpmxevcntr, CLUSTERPMXEVCNTR)
DEFINE_COPROCR_RW_FUNCS(clusterpmxevtyper, CLUSTERPMXEVTYPER)
/* /*
* RNDR is AArch64 only, so just provide a placeholder here to make the * RNDR is AArch64 only, so just provide a placeholder here to make the

View file

@ -1482,4 +1482,17 @@
/* alternative system register encoding for the "sb" speculation barrier */ /* alternative system register encoding for the "sb" speculation barrier */
#define SYSREG_SB S0_3_C3_C0_7 #define SYSREG_SB S0_3_C3_C0_7
#define CLUSTERPMCR_EL1 S3_0_C15_C5_0
#define CLUSTERPMCNTENSET_EL1 S3_0_C15_C5_1
#define CLUSTERPMCCNTR_EL1 S3_0_C15_C6_0
#define CLUSTERPMOVSSET_EL1 S3_0_C15_C5_3
#define CLUSTERPMOVSCLR_EL1 S3_0_C15_C5_4
#define CLUSTERPMSELR_EL1 S3_0_C15_C5_5
#define CLUSTERPMXEVTYPER_EL1 S3_0_C15_C6_1
#define CLUSTERPMXEVCNTR_EL1 S3_0_C15_C6_2
#define CLUSTERPMCR_E_BIT BIT(0)
#define CLUSTERPMCR_N_SHIFT U(11)
#define CLUSTERPMCR_N_MASK U(0x1f)
#endif /* ARCH_H */ #endif /* ARCH_H */

View file

@ -663,8 +663,16 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(gcscre0_el1, GCSCRE0_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el1, GCSPR_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el1, GCSPR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el0, GCSPR_EL0) DEFINE_RENAME_SYSREG_RW_FUNCS(gcspr_el0, GCSPR_EL0)
/* DynamIQ Shared Unit power management */ /* DynamIQ Control registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1) DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmcr_el1, CLUSTERPMCR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmcntenset_el1, CLUSTERPMCNTENSET_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmccntr_el1, CLUSTERPMCCNTR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmovsset_el1, CLUSTERPMOVSSET_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmovsclr_el1, CLUSTERPMOVSCLR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmselr_el1, CLUSTERPMSELR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmxevcntr_el1, CLUSTERPMXEVCNTR_EL1)
DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpmxevtyper_el1, CLUSTERPMXEVTYPER_EL1)
/* CPU Power/Performance Management registers */ /* CPU Power/Performance Management registers */
DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3)
@ -827,8 +835,32 @@ void gpt_tlbi_by_pa_ll(uint64_t pa, size_t size);
#define read_cpacr() read_cpacr_el1() #define read_cpacr() read_cpacr_el1()
#define write_cpacr(_v) write_cpacr_el1(_v) #define write_cpacr(_v) write_cpacr_el1(_v)
#define read_clusterpwrdn() read_clusterpwrdn_el1() #define read_clusterpwrdn() read_clusterpwrdn_el1()
#define write_clusterpwrdn(_v) write_clusterpwrdn_el1(_v) #define write_clusterpwrdn(_v) write_clusterpwrdn_el1(_v)
#define read_clusterpmcr() read_clusterpmcr_el1()
#define write_clusterpmcr(_v) write_clusterpmcr_el1(_v)
#define read_clusterpmcntenset() read_clusterpmcntenset_el1()
#define write_clusterpmcntenset(_v) write_clusterpmcntenset_el1(_v)
#define read_clusterpmccntr() read_clusterpmccntr_el1()
#define write_clusterpmccntr(_v) write_clusterpmccntr_el1(_v)
#define read_clusterpmovsset() read_clusterpmovsset_el1()
#define write_clusterpmovsset(_v) write_clusterpmovsset_el1(_v)
#define read_clusterpmovsclr() read_clusterpmovsclr_el1()
#define write_clusterpmovsclr(_v) write_clusterpmovsclr_el1(_v)
#define read_clusterpmselr() read_clusterpmselr_el1()
#define write_clusterpmselr(_v) write_clusterpmselr_el1(_v)
#define read_clusterpmxevcntr() read_clusterpmxevcntr_el1()
#define write_clusterpmxevcntr(_v) write_clusterpmxevcntr_el1(_v)
#define read_clusterpmxevtyper() read_clusterpmxevtyper_el1()
#define write_clusterpmxevtyper(_v) write_clusterpmxevtyper_el1(_v)
#if ERRATA_SPECULATIVE_AT #if ERRATA_SPECULATIVE_AT
/* /*

View file

@ -0,0 +1,42 @@
/*
* Copyright (c) 2024, Arm Limited and Contributors. All rights reserved.
*
* SPDX-License-Identifier: BSD-3-Clause
*/
#ifndef DSU_H
#define DSU_H
#define PMCR_N_MAX 0x1f
#define save_pmu_reg(state, reg) state->reg = read_##reg()
#define restore_pmu_reg(context, reg) write_##reg(context->reg)
typedef struct cluster_pmu_state{
uint64_t clusterpmcr;
uint64_t clusterpmcntenset;
uint64_t clusterpmccntr;
uint64_t clusterpmovsset;
uint64_t clusterpmselr;
uint64_t clusterpmsevtyper;
uint64_t counter_val[PMCR_N_MAX];
uint64_t counter_type[PMCR_N_MAX];
} cluster_pmu_state_t;
static inline unsigned int read_cluster_eventctr_num(void)
{
return ((read_clusterpmcr() >> CLUSTERPMCR_N_SHIFT) &
CLUSTERPMCR_N_MASK);
}
void save_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
void restore_dsu_pmu_state(cluster_pmu_state_t *cluster_pmu_context);
void cluster_on_dsu_pmu_context_restore(void);
void cluster_off_dsu_pmu_context_save(void);
#endif /* DSU_H */

View file

@ -383,6 +383,8 @@ int arm_get_rotpk_info_dev(void **key_ptr, unsigned int *key_len,
unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr); unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr);
#endif #endif
unsigned int plat_cluster_id_by_mpidr(u_register_t mpidr);
/* /*
* This function is called after loading SCP_BL2 image and it is used to perform * This function is called after loading SCP_BL2 image and it is used to perform
* any platform-specific actions required to handle the SCP firmware. * any platform-specific actions required to handle the SCP firmware.

View file

@ -395,3 +395,7 @@ PLATFORM_REPORT_CTX_MEM_USE := 0
# Enable early console # Enable early console
EARLY_CONSOLE := 0 EARLY_CONSOLE := 0
# Allow platforms to save/restore DSU PMU registers over a power cycle.
# Disabled by default and must be enabled by individual platforms.
PRESERVE_DSU_PMU_REGS := 0

View file

@ -68,6 +68,9 @@ $(eval $(call add_defines, \
CSS_LOAD_SCP_IMAGES := 1 CSS_LOAD_SCP_IMAGES := 1
# Save DSU PMU registers on cluster off and restore them on cluster on
PRESERVE_DSU_PMU_REGS := 1
# Include GICv3 driver files # Include GICv3 driver files
include drivers/arm/gic/v3/gicv3.mk include drivers/arm/gic/v3/gicv3.mk
@ -128,6 +131,7 @@ BL31_SOURCES += ${INTERCONNECT_SOURCES} \
${TC_BASE}/tc_topology.c \ ${TC_BASE}/tc_topology.c \
lib/fconf/fconf.c \ lib/fconf/fconf.c \
lib/fconf/fconf_dyn_cfg_getter.c \ lib/fconf/fconf_dyn_cfg_getter.c \
drivers/arm/css/dsu/dsu.c \
drivers/cfi/v2m/v2m_flash.c \ drivers/cfi/v2m/v2m_flash.c \
lib/utils/mem_region.c \ lib/utils/mem_region.c \
plat/arm/common/arm_nor_psci_mem_protect.c \ plat/arm/common/arm_nor_psci_mem_protect.c \

View file

@ -65,3 +65,11 @@ unsigned int plat_arm_get_cpu_pe_count(u_register_t mpidr)
return PLAT_MAX_PE_PER_CPU; return PLAT_MAX_PE_PER_CPU;
} }
#endif #endif
/******************************************************************************
* Return the cluster ID of current CPU
*****************************************************************************/
unsigned int plat_cluster_id_by_mpidr(u_register_t mpidr)
{
return MPIDR_AFFLVL2_VAL(mpidr);
}

View file

@ -12,6 +12,7 @@
#include <bl31/interrupt_mgmt.h> #include <bl31/interrupt_mgmt.h>
#include <common/debug.h> #include <common/debug.h>
#include <drivers/arm/css/css_scp.h> #include <drivers/arm/css/css_scp.h>
#include <drivers/arm/css/dsu.h>
#include <lib/cassert.h> #include <lib/cassert.h>
#include <plat/arm/common/plat_arm.h> #include <plat/arm/common/plat_arm.h>
@ -82,8 +83,12 @@ static void css_pwr_domain_on_finisher_common(
* Perform the common cluster specific operations i.e enable coherency * Perform the common cluster specific operations i.e enable coherency
* if this cluster was off. * if this cluster was off.
*/ */
if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
#if PRESERVE_DSU_PMU_REGS
cluster_on_dsu_pmu_context_restore();
#endif
plat_arm_interconnect_enter_coherency(); plat_arm_interconnect_enter_coherency();
}
} }
/******************************************************************************* /*******************************************************************************
@ -131,8 +136,12 @@ static void css_power_down_common(const psci_power_state_t *target_state)
plat_arm_gic_cpuif_disable(); plat_arm_gic_cpuif_disable();
/* Cluster is to be turned off, so disable coherency */ /* Cluster is to be turned off, so disable coherency */
if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) if (CSS_CLUSTER_PWR_STATE(target_state) == ARM_LOCAL_STATE_OFF) {
#if PRESERVE_DSU_PMU_REGS
cluster_off_dsu_pmu_context_save();
#endif
plat_arm_interconnect_exit_coherency(); plat_arm_interconnect_exit_coherency();
}
} }
/******************************************************************************* /*******************************************************************************