feat(dsu): save/restore DSU PMU register

Adds driver support to preserve DSU PMU register values over a DSU
power cycle. This driver needs to be enabled by the platforms that
support DSU and also need it's PMU registers to be preserved

Change-Id: I7fc68a3d7d99ee369379aa5cd114fffc763fc0d2
Signed-off-by: Arvind Ram Prakash <arvind.ramprakash@arm.com>
This commit is contained in:
Arvind Ram Prakash 2023-12-21 00:25:52 -06:00
parent e6ae019a84
commit f99a69c386
9 changed files with 260 additions and 5 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

@ -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