Re: [PATCH v2 1/2] arm64: cpufeature: Add support for the MPAM v0.1 architecture version
From: James Morse
Date: Thu May 07 2026 - 10:09:44 EST
Hi Zeng,
(sorry for the delay - arm silently blocked your original mail. I've added you
to the whitelist, we'll see if that actually does anything!)
On 03/02/2026 09:54, Zeng Heng wrote:
> According to the MPAM spec [1], the supported architecture versions are
> v1.0, v1.1 and v0.1. MPAM versions v0.1 and v1.1 are functionally
> identical, but v0.1 additionally supports the FORCE_NS feature.
>
> ID_AA64PR | ID_AA64PR | MPAM Extension | Notes
> F0_EL1. | F1_EL1. | Architecture |
> MPAM | MPAM_frac | version |
> ---------------------------------------------------------------------------
> 0b0000 | 0b0001 | v0.1 | MPAM v0.1 is implemented.
> | | | MPAM v0.1 is the same as MPAM v1.1
> | | | with FORCE_NS which is
> | | | incompatible with MPAM v1.0.
> ---------------------------------------------------------------------------
> 0b0001 | 0b0000 | v1.0 | MPAM v1.0 is implemented.
> ---------------------------------------------------------------------------
> 0b0001 | 0b0001 | v1.1 | MPAM v1.1 is implemented.
> | | | MPAM v1.1 includes all features of
> | | | MPAM v1.0.
> | | | It must not include FORCE_NS.
>
> FORCE_NS is a feature that operates in EL3 mode. Consequently, the current
> Linux MPAM driver is also compatible with MPAM v0.1. To support v0.1, the
> existing driver which only checks ID_AA64PFR0_EL1.MPAM for the major
> version needs to examine ID_AA64PFR1_EL1.MPAM_frac for the minor version
> as well.
>
> [1] https://developer.arm.com/documentation/ddi0598/db/?lang=en
> diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h
> index cacd20df1786..606cf14e4044 100644
> --- a/arch/arm64/include/asm/el2_setup.h
> +++ b/arch/arm64/include/asm/el2_setup.h
> @@ -501,7 +501,9 @@
> #endif
>
> .macro finalise_el2_state
> - check_override id_aa64pfr0, ID_AA64PFR0_EL1_MPAM_SHIFT, .Linit_mpam_\@, .Lskip_mpam_\@, x1, x2
> + check_override id_aa64pfr0, ID_AA64PFR0_EL1_MPAM_SHIFT, .Linit_mpam_\@, .Lmpam_minor_\@, x1, x2
> +.Lmpam_minor_\@:
> + check_override id_aa64pfr1, ID_AA64PFR1_EL1_MPAM_frac_SHIFT, .Linit_mpam_\@, .Lskip_mpam_\@, x1, x2
Heh, I see the 'frac' field already has an override.
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index c840a93b9ef9..e8fa6f7cf2a2 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1159,6 +1159,14 @@ static __init void detect_system_supports_pseudo_nmi(void)
> static inline void detect_system_supports_pseudo_nmi(void) { }
> #endif
>
> +static bool detect_ftr_has_mpam(void)
> +{
> + u64 pfr0 = read_sanitised_ftr_reg(SYS_ID_AA64PFR0_EL1);
> + u64 pfr1 = read_sanitised_ftr_reg(SYS_ID_AA64PFR1_EL1);
> +
> + return id_aa64pfr0_mpam(pfr0) || id_aa64pfr1_mpamfrac(pfr1);
> +}
> +
> void __init init_cpu_features(struct cpuinfo_arm64 *info)
> {
> /* Before we start using the tables, make sure it is sorted */
> @@ -2473,7 +2481,7 @@ cpucap_panic_on_conflict(const struct arm64_cpu_capabilities *cap)
> static bool
> test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope)
> {
> - if (!has_cpuid_feature(entry, scope))
> + if (!detect_ftr_has_mpam())
> return false;
>
> /* Check firmware actually enabled MPAM on this cpu. */
> @@ -3078,7 +3086,6 @@ static const struct arm64_cpu_capabilities arm64_features[] = {
> .capability = ARM64_MPAM,
> .matches = test_has_mpam,
> .cpu_enable = cpu_enable_mpam,
> - ARM64_CPUID_FIELDS(ID_AA64PFR0_EL1, MPAM, 1)
> },
> {
> .desc = "Memory Partitioning And Monitoring Virtualisation",
I think this is preferable to a 'metacap' as the pointer auth code does - we never need
to expose the difference between MPAM v0.1 and v1.x to anything.
Reviewed-by: James Morse <james.morse@xxxxxxx>
Thanks,
James