diff --git a/Makefile b/Makefile index 21de8625f..0caa9c08e 100644 --- a/Makefile +++ b/Makefile @@ -1015,6 +1015,8 @@ $(eval $(call assert_booleans,\ ENABLE_SYS_REG_TRACE_FOR_NS \ ENABLE_TRF_FOR_NS \ ENABLE_FEAT_HCX \ + ENABLE_MPMM \ + ENABLE_MPMM_FCONF \ ))) $(eval $(call assert_numerics,\ @@ -1123,6 +1125,8 @@ $(eval $(call add_defines,\ ENABLE_SYS_REG_TRACE_FOR_NS \ ENABLE_TRF_FOR_NS \ ENABLE_FEAT_HCX \ + ENABLE_MPMM \ + ENABLE_MPMM_FCONF \ ))) ifeq (${SANITIZE_UB},trap) diff --git a/bl31/bl31.mk b/bl31/bl31.mk index 4e9e99f46..9baa0c27f 100644 --- a/bl31/bl31.mk +++ b/bl31/bl31.mk @@ -23,6 +23,7 @@ ifeq (${SPM_MM},1) endif include lib/extensions/amu/amu.mk +include lib/mpmm/mpmm.mk include lib/psci/psci_lib.mk BL31_SOURCES += bl31/bl31_main.c \ @@ -82,6 +83,10 @@ ifeq (${ENABLE_AMU},1) BL31_SOURCES += ${AMU_SOURCES} endif +ifeq (${ENABLE_MPMM},1) +BL31_SOURCES += ${MPMM_SOURCES} +endif + ifeq (${ENABLE_SVE_FOR_NS},1) BL31_SOURCES += lib/extensions/sve/sve.c endif diff --git a/docs/components/activity-monitors.rst b/docs/components/activity-monitors.rst index ee280e287..dd45c4353 100644 --- a/docs/components/activity-monitors.rst +++ b/docs/components/activity-monitors.rst @@ -10,6 +10,8 @@ When the ``ENABLE_AMU=1`` build option is provided, Trusted Firmware-A sets up the |AMU| prior to its exit from EL3, and will save and restore architected |AMU| counters as necessary upon suspend and resume. +.. _Activity Monitor Auxiliary Counters: + Auxiliary counters ------------------ diff --git a/docs/components/fconf/index.rst b/docs/components/fconf/index.rst index 00a4e297b..029f324dc 100644 --- a/docs/components/fconf/index.rst +++ b/docs/components/fconf/index.rst @@ -146,3 +146,4 @@ Properties binding information fconf_properties amu-bindings + mpmm-bindings diff --git a/docs/components/fconf/mpmm-bindings.rst b/docs/components/fconf/mpmm-bindings.rst new file mode 100644 index 000000000..d3cc857a8 --- /dev/null +++ b/docs/components/fconf/mpmm-bindings.rst @@ -0,0 +1,48 @@ +Maximum Power Mitigation Mechanism (MPMM) Bindings +================================================== + +|MPMM| support cannot be determined at runtime by the firmware. Instead, these +DTB bindings allow the platform to communicate per-core support for |MPMM| via +the ``HW_CONFIG`` device tree blob. + +Bindings +^^^^^^^^ + +.. contents:: + :local: + +``/cpus/cpus/cpu*`` node properties +""""""""""""""""""""""""""""""""""" + +The ``cpu`` node has been augmented to allow the platform to indicate support +for |MPMM| on a given core. + ++-------------------+-------+-------------+------------------------------------+ +| Property name | Usage | Value type | Description | ++===================+=======+=============+====================================+ +| ``supports-mpmm`` | O | ```` | If present, indicates that |MPMM| | +| | | | is available on this core. | ++-------------------+-------+-------------+------------------------------------+ + +Example +^^^^^^^ + +An example system offering two cores, one with support for |MPMM| and one +without, can be described as follows: + +.. code-block:: + + cpus { + #address-cells = <2>; + #size-cells = <0>; + + cpu0@00000 { + ... + + supports-mpmm; + }; + + cpu1@00100 { + ... + }; + } diff --git a/docs/components/index.rst b/docs/components/index.rst index e46751651..754526daf 100644 --- a/docs/components/index.rst +++ b/docs/components/index.rst @@ -14,6 +14,7 @@ Components fconf/index firmware-update measured_boot/index + mpmm platform-interrupt-controller-API ras romlib-design diff --git a/docs/components/mpmm.rst b/docs/components/mpmm.rst new file mode 100644 index 000000000..1b1c6d8c7 --- /dev/null +++ b/docs/components/mpmm.rst @@ -0,0 +1,30 @@ +Maximum Power Mitigation Mechanism (MPMM) +^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + +|MPMM| is an optional microarchitectural power management mechanism supported by +some Arm Armv9-A cores, beginning with the Cortex-X2, Cortex-A710 and +Cortex-A510 cores. This mechanism detects and limits high-activity events to +assist in |SoC| processor power domain dynamic power budgeting and limit the +triggering of whole-rail (i.e. clock chopping) responses to overcurrent +conditions. + +|MPMM| is enabled on a per-core basis by the EL3 runtime firmware. The presence +of |MPMM| cannot be determined at runtime by the firmware, and therefore the +platform must expose this information through one of two possible mechanisms: + +- |FCONF|, controlled by the ``ENABLE_MPMM_FCONF`` build option. +- A platform implementation of the ``plat_mpmm_topology`` function (the + default). + +See :ref:`Maximum Power Mitigation Mechanism (MPMM) Bindings` for documentation +on the |FCONF| device tree bindings. + +.. warning:: + + |MPMM| exposes gear metrics through the auxiliary |AMU| counters. An + external power controller can use these metrics to budget SoC power by + limiting the number of cores that can execute higher-activity workloads or + switching to a different DVFS operating point. When this is the case, the + |AMU| counters that make up the |MPMM| gears must be enabled by the EL3 + runtime firmware - please see :ref:`Activity Monitor Auxiliary Counters` for + documentation on enabling auxiliary |AMU| counters. diff --git a/docs/getting_started/build-options.rst b/docs/getting_started/build-options.rst index 8a0167b6d..da8d554db 100644 --- a/docs/getting_started/build-options.rst +++ b/docs/getting_started/build-options.rst @@ -265,6 +265,16 @@ Common build options partitioning in EL3, however. Platform initialisation code should configure and use partitions in EL3 as required. This option defaults to ``0``. +- ``ENABLE_MPMM``: Boolean option to enable support for the Maximum Power + Mitigation Mechanism supported by certain Arm cores, which allows the SoC + firmware to detect and limit high activity events to assist in SoC processor + power domain dynamic power budgeting and limit the triggering of whole-rail + (i.e. clock chopping) responses to overcurrent conditions. Defaults to ``0``. + +- ``ENABLE_MPMM_FCONF``: Enables configuration of MPMM through FCONF, which + allows platforms with cores supporting MPMM to describe them via the + ``HW_CONFIG`` device tree blob. Default is 0. + - ``ENABLE_PIE``: Boolean option to enable Position Independent Executable(PIE) support within generic code in TF-A. This option is currently only supported in BL2_AT_EL3, BL31, and BL32 (TSP) for AARCH64 binaries, and in BL32 diff --git a/docs/global_substitutions.txt b/docs/global_substitutions.txt index a70f15e3d..af1514675 100644 --- a/docs/global_substitutions.txt +++ b/docs/global_substitutions.txt @@ -25,6 +25,7 @@ .. |Linaro| replace:: :term:`Linaro` .. |MMU| replace:: :term:`MMU` .. |MPAM| replace:: :term:`MPAM` +.. |MPMM| replace:: :term:`MPMM` .. |MPIDR| replace:: :term:`MPIDR` .. |MTE| replace:: :term:`MTE` .. |OEN| replace:: :term:`OEN` diff --git a/docs/glossary.rst b/docs/glossary.rst index a062319ce..aeeb133cb 100644 --- a/docs/glossary.rst +++ b/docs/glossary.rst @@ -92,6 +92,10 @@ You can find additional definitions in the `Arm Glossary`_. MPAM Memory Partitioning And Monitoring. An optional Armv8.4 extension. + MPMM + Maximum Power Mitigation Mechanism, an optional power management mechanism + supported by some Arm Armv9-A cores. + MPIDR Multiprocessor Affinity Register diff --git a/include/arch/aarch64/arch.h b/include/arch/aarch64/arch.h index 8b362f1cc..5408acf82 100644 --- a/include/arch/aarch64/arch.h +++ b/include/arch/aarch64/arch.h @@ -1216,4 +1216,16 @@ #define DSU_CLUSTER_PWR_ON 1 #define DSU_CLUSTER_PWR_MASK U(1) +/******************************************************************************* + * Definitions for CPU Power/Performance Management registers + ******************************************************************************/ + +#define CPUPPMCR_EL3 S3_6_C15_C2_0 +#define CPUPPMCR_EL3_MPMMPINCTL_SHIFT UINT64_C(0) +#define CPUPPMCR_EL3_MPMMPINCTL_MASK UINT64_C(0x1) + +#define CPUMPMMCR_EL3 S3_6_C15_C2_1 +#define CPUMPMMCR_EL3_MPMM_EN_SHIFT UINT64_C(0) +#define CPUMPMMCR_EL3_MPMM_EN_MASK UINT64_C(0x1) + #endif /* ARCH_H */ diff --git a/include/arch/aarch64/arch_helpers.h b/include/arch/aarch64/arch_helpers.h index cae05dc2e..37fa047c3 100644 --- a/include/arch/aarch64/arch_helpers.h +++ b/include/arch/aarch64/arch_helpers.h @@ -542,6 +542,10 @@ DEFINE_RENAME_SYSREG_RW_FUNCS(hcrx_el2, HCRX_EL2) /* DynamIQ Shared Unit power management */ DEFINE_RENAME_SYSREG_RW_FUNCS(clusterpwrdn_el1, CLUSTERPWRDN_EL1) +/* CPU Power/Performance Management registers */ +DEFINE_RENAME_SYSREG_RW_FUNCS(cpuppmcr_el3, CPUPPMCR_EL3) +DEFINE_RENAME_SYSREG_RW_FUNCS(cpumpmmcr_el3, CPUMPMMCR_EL3) + /* Armv9.2 RME Registers */ DEFINE_RENAME_SYSREG_RW_FUNCS(gptbr_el3, GPTBR_EL3) DEFINE_RENAME_SYSREG_RW_FUNCS(gpccr_el3, GPCCR_EL3) diff --git a/include/lib/fconf/fconf_mpmm_getter.h b/include/lib/fconf/fconf_mpmm_getter.h new file mode 100644 index 000000000..50d991a2f --- /dev/null +++ b/include/lib/fconf/fconf_mpmm_getter.h @@ -0,0 +1,20 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef FCONF_MPMM_GETTER_H +#define FCONF_MPMM_GETTER_H + +#include + +#define mpmm__config_getter(id) fconf_mpmm_config.id + +struct fconf_mpmm_config { + const struct mpmm_topology *topology; +}; + +extern struct fconf_mpmm_config fconf_mpmm_config; + +#endif /* FCONF_MPMM_GETTER_H */ diff --git a/include/lib/mpmm/mpmm.h b/include/lib/mpmm/mpmm.h new file mode 100644 index 000000000..955c530e8 --- /dev/null +++ b/include/lib/mpmm/mpmm.h @@ -0,0 +1,57 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#ifndef MPMM_H +#define MPMM_H + +#include + +#include + +/* + * Enable the Maximum Power Mitigation Mechanism. + * + * This function will enable MPMM for the current core. The AMU counters + * representing the MPMM gears must have been configured and enabled prior to + * calling this function. + */ +void mpmm_enable(void); + +/* + * MPMM core data. + * + * This structure represents per-core data retrieved from the hardware + * configuration device tree. + */ +struct mpmm_core { + /* + * Whether MPMM is supported. + * + * Cores with support for MPMM offer one or more auxiliary AMU counters + * representing MPMM gears. + */ + bool supported; +}; + +/* + * MPMM topology. + * + * This topology structure describes the system-wide representation of the + * information retrieved from the hardware configuration device tree. + */ +struct mpmm_topology { + struct mpmm_core cores[PLATFORM_CORE_COUNT]; /* Per-core data */ +}; + +#if !ENABLE_MPMM_FCONF +/* + * Retrieve the platform's MPMM topology. A `NULL` return value is treated as a + * non-fatal error, in which case MPMM will not be enabled for any core. + */ +const struct mpmm_topology *plat_mpmm_topology(void); +#endif /* ENABLE_MPMM_FCONF */ + +#endif /* MPMM_H */ diff --git a/lib/extensions/amu/aarch64/amu.c b/lib/extensions/amu/aarch64/amu.c index f7125204a..35efd21e0 100644 --- a/lib/extensions/amu/aarch64/amu.c +++ b/lib/extensions/amu/aarch64/amu.c @@ -23,6 +23,10 @@ # include #endif +#if ENABLE_MPMM +# include +#endif + struct amu_ctx { uint64_t group0_cnts[AMU_GROUP0_MAX_COUNTERS]; #if ENABLE_AMU_AUXILIARY_COUNTERS @@ -273,26 +277,31 @@ void amu_enable(bool el2_unused, cpu_context_t *ctx) /* Initialize FEAT_AMUv1p1 features if present. */ if (id_aa64pfr0_el1_amu >= ID_AA64PFR0_AMU_V1P1) { - return; - } - - if (el2_unused) { - /* Make sure virtual offsets are disabled if EL2 not used. */ - write_hcr_el2_amvoffen(0U); - } + if (el2_unused) { + /* + * Make sure virtual offsets are disabled if EL2 not + * used. + */ + write_hcr_el2_amvoffen(0U); + } #if AMU_RESTRICT_COUNTERS - /* - * FEAT_AMUv1p1 adds a register field to restrict access to group 1 - * counters at all but the highest implemented EL. This is controlled - * with the AMU_RESTRICT_COUNTERS compile time flag, when set, system - * register reads at lower ELs return zero. Reads from the memory - * mapped view are unaffected. - */ - VERBOSE("AMU group 1 counter access restricted.\n"); - write_amcr_el0_cg1rz(1U); + /* + * FEAT_AMUv1p1 adds a register field to restrict access to + * group 1 counters at all but the highest implemented EL. This + * is controlled with the `AMU_RESTRICT_COUNTERS` compile time + * flag, when set, system register reads at lower ELs return + * zero. Reads from the memory mapped view are unaffected. + */ + VERBOSE("AMU group 1 counter access restricted.\n"); + write_amcr_el0_cg1rz(1U); #else - write_amcr_el0_cg1rz(0U); + write_amcr_el0_cg1rz(0U); +#endif + } + +#if ENABLE_MPMM + mpmm_enable(); #endif } @@ -616,6 +625,10 @@ static void *amu_context_restore(const void *arg) } #endif +#if ENABLE_MPMM + mpmm_enable(); +#endif + return (void *)0; } diff --git a/lib/fconf/fconf.mk b/lib/fconf/fconf.mk index 18bcb3590..fb8891031 100644 --- a/lib/fconf/fconf.mk +++ b/lib/fconf/fconf.mk @@ -14,3 +14,6 @@ FCONF_DYN_SOURCES += ${FDT_WRAPPERS_SOURCES} FCONF_AMU_SOURCES := lib/fconf/fconf_amu_getter.c FCONF_AMU_SOURCES += ${FDT_WRAPPERS_SOURCES} + +FCONF_MPMM_SOURCES := lib/fconf/fconf_mpmm_getter.c +FCONF_MPMM_SOURCES += ${FDT_WRAPPERS_SOURCES} diff --git a/lib/fconf/fconf_mpmm_getter.c b/lib/fconf/fconf_mpmm_getter.c new file mode 100644 index 000000000..02a566d5a --- /dev/null +++ b/lib/fconf/fconf_mpmm_getter.c @@ -0,0 +1,80 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include +#include + +#include +#include +#include +#include +#include + +#include + +struct fconf_mpmm_config fconf_mpmm_config; +static struct mpmm_topology fconf_mpmm_topology; + +/* + * Within a `cpu` node, determine support for MPMM via the `supports-mpmm` + * property. + * + * Returns `0` on success, or a negative integer representing an error code. + */ +static int fconf_populate_mpmm_cpu(const void *fdt, int off, uintptr_t mpidr) +{ + int ret, len; + + int core_pos; + struct mpmm_core *core; + + core_pos = plat_core_pos_by_mpidr(mpidr); + if (core_pos < 0) { + return -FDT_ERR_BADVALUE; + } + + core = &fconf_mpmm_topology.cores[core_pos]; + + fdt_getprop(fdt, off, "supports-mpmm", &len); + if (len >= 0) { + core->supported = true; + ret = 0; + } else { + core->supported = false; + ret = len; + } + + return ret; +} + +/* + * Populates the global `fconf_mpmm_config` structure based on what's described + * by the hardware configuration device tree blob. + * + * The device tree is expected to provide a `supports-mpmm` property for each + * `cpu` node, like so: + * + * cpu@0 { + * supports-mpmm; + * }; + * + * This property indicates whether the core implements MPMM, as we cannot detect + * support for it dynamically. + */ +static int fconf_populate_mpmm(uintptr_t config) +{ + int ret = fdtw_for_each_cpu( + (const void *)config, fconf_populate_mpmm_cpu); + if (ret == 0) { + fconf_mpmm_config.topology = &fconf_mpmm_topology; + } else { + ERROR("FCONF: failed to configure MPMM: %d\n", ret); + } + + return ret; +} + +FCONF_REGISTER_POPULATOR(HW_CONFIG, mpmm, fconf_populate_mpmm); diff --git a/lib/mpmm/mpmm.c b/lib/mpmm/mpmm.c new file mode 100644 index 000000000..a66f2aad3 --- /dev/null +++ b/lib/mpmm/mpmm.c @@ -0,0 +1,72 @@ +/* + * Copyright (c) 2021, Arm Limited. All rights reserved. + * + * SPDX-License-Identifier: BSD-3-Clause + */ + +#include + +#include +#include + +#include + +#if ENABLE_MPMM_FCONF +# include +# include +#endif + +static uint64_t read_cpuppmcr_el3_mpmmpinctl(void) +{ + return (read_cpuppmcr_el3() >> CPUPPMCR_EL3_MPMMPINCTL_SHIFT) & + CPUPPMCR_EL3_MPMMPINCTL_MASK; +} + +static void write_cpumpmmcr_el3_mpmm_en(uint64_t mpmm_en) +{ + uint64_t value = read_cpumpmmcr_el3(); + + value &= ~(CPUMPMMCR_EL3_MPMM_EN_MASK << CPUMPMMCR_EL3_MPMM_EN_SHIFT); + value |= (mpmm_en & CPUMPMMCR_EL3_MPMM_EN_MASK) << + CPUMPMMCR_EL3_MPMM_EN_SHIFT; + + write_cpumpmmcr_el3(value); +} + +static bool mpmm_supported(void) +{ + bool supported = false; + const struct mpmm_topology *topology; + +#if ENABLE_MPMM_FCONF + topology = FCONF_GET_PROPERTY(mpmm, config, topology); +#else + topology = plat_mpmm_topology(); +#endif /* ENABLE_MPMM_FCONF */ + + /* + * For the current core firstly try to find out if the platform + * configuration has claimed support for MPMM, then make sure that MPMM + * is controllable through the system registers. + */ + + if (topology != NULL) { + unsigned int core_pos = plat_my_core_pos(); + + supported = topology->cores[core_pos].supported && + (read_cpuppmcr_el3_mpmmpinctl() == 0U); + } else { + ERROR("MPMM: failed to generate MPMM topology\n"); + } + + return supported; +} + +void mpmm_enable(void) +{ + bool supported = mpmm_supported(); + + if (supported) { + write_cpumpmmcr_el3_mpmm_en(1U); + } +} diff --git a/lib/mpmm/mpmm.mk b/lib/mpmm/mpmm.mk new file mode 100644 index 000000000..826f9253b --- /dev/null +++ b/lib/mpmm/mpmm.mk @@ -0,0 +1,29 @@ +# +# Copyright (c) 2021, Arm Limited. All rights reserved. +# +# SPDX-License-Identifier: BSD-3-Clause +# + +include lib/extensions/amu/amu.mk +include lib/fconf/fconf.mk + +ifneq (${ENABLE_MPMM},0) + ifneq ($(ARCH),aarch64) + $(error MPMM support (`ENABLE_MPMM`) can only be enabled in AArch64 images (`ARCH`)) + endif + + ifeq (${ENABLE_AMU_AUXILIARY_COUNTERS},0) # For MPMM gear AMU counters + $(error MPMM support (`ENABLE_MPM`) requires auxiliary AMU counter support (`ENABLE_AMU_AUXILIARY_COUNTERS`)) + endif +endif + +MPMM_SOURCES := lib/mpmm/mpmm.c +MPMM_SOURCES += ${AMU_SOURCES} + +ifneq (${ENABLE_MPMM_FCONF},0) + ifeq (${ENABLE_MPMM},0) + $(error MPMM FCONF support (`ENABLE_MPMM_FCONF`) requires MPMM support (`ENABLE_MPMM`)) + endif + + MPMM_SOURCES += ${FCONF_MPMM_SOURCES} +endif diff --git a/make_helpers/defaults.mk b/make_helpers/defaults.mk index 8705d9247..45f5fa87f 100644 --- a/make_helpers/defaults.mk +++ b/make_helpers/defaults.mk @@ -96,6 +96,12 @@ DYN_DISABLE_AUTH := 0 # Build option to enable MPAM for lower ELs ENABLE_MPAM_FOR_LOWER_ELS := 0 +# Enable the Maximum Power Mitigation Mechanism on supporting cores. +ENABLE_MPMM := 0 + +# Enable MPMM configuration via FCONF. +ENABLE_MPMM_FCONF := 0 + # Flag to Enable Position Independant support (PIE) ENABLE_PIE := 0