diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index 2af4c7ad7dc59c8121d8c242af07eb7718dff4f7..f8ec4b20fa696810cbe64580d1fb4c8d7aa55c20 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -858,6 +858,15 @@ static inline bool cpus_support_mpam(void) cpus_have_final_cap(ARM64_MPAM); } +#ifdef CONFIG_ARM64_MPAM +bool mpam_detect_is_enabled(void); +#else +static inline bool mpam_detect_is_enabled(void) +{ + return false; +} +#endif + int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt); bool try_emulate_mrs(struct pt_regs *regs, u32 isn); diff --git a/arch/arm64/include/asm/el2_setup.h b/arch/arm64/include/asm/el2_setup.h index 3dc7c58d55b6a1f9be084f34d0220a918a8c29f4..e4546b29dd0cbfbb5b902e15caadab69458b1fac 100644 --- a/arch/arm64/include/asm/el2_setup.h +++ b/arch/arm64/include/asm/el2_setup.h @@ -209,21 +209,6 @@ msr spsr_el2, x0 .endm -.macro __init_el2_mpam -#ifdef CONFIG_ARM64_MPAM - /* Memory Partioning And Monitoring: disable EL2 traps */ - mrs x1, id_aa64pfr0_el1 - ubfx x0, x1, #ID_AA64PFR0_EL1_MPAM_SHIFT, #4 - cbz x0, .Lskip_mpam_\@ // skip if no MPAM - msr_s SYS_MPAM2_EL2, xzr // use the default partition - // and disable lower traps - mrs_s x0, SYS_MPAMIDR_EL1 - tbz x0, #17, .Lskip_mpam_\@ // skip if no MPAMHCR reg - msr_s SYS_MPAMHCR_EL2, xzr // clear TRAP_MPAMIDR_EL1 -> EL2 -.Lskip_mpam_\@: -#endif /* CONFIG_ARM64_MPAM */ -.endm - /** * Initialize EL2 registers to sane values. This should be called early on all * cores that were booted in EL2. Note that everything gets initialised as @@ -241,7 +226,6 @@ __init_el2_stage2 __init_el2_gicv3 __init_el2_hstr - __init_el2_mpam __init_el2_nvhe_idregs __init_el2_cptr __init_el2_fgt diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index f94bc6eb83e0da40360514a1847c0c9a95118b93..f4f3ad6703919446ee8d71a7659e235a9772a912 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -1078,8 +1078,9 @@ void __init init_cpu_features(struct cpuinfo_arm64 *info) vec_init_vq_map(ARM64_VEC_SME); } - if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0) || - id_aa64pfr1_mpamfrac(info->reg_id_aa64pfr1)) + if (mpam_detect_is_enabled() && + (id_aa64pfr0_mpam(info->reg_id_aa64pfr0) || + id_aa64pfr1_mpamfrac(info->reg_id_aa64pfr1))) init_cpu_ftr_reg(SYS_MPAMIDR_EL1, info->reg_mpamidr); if (id_aa64pfr1_mte(info->reg_id_aa64pfr1)) @@ -1341,8 +1342,9 @@ void update_cpu_features(int cpu, vec_update_vq_map(ARM64_VEC_SME); } - if (id_aa64pfr0_mpam(info->reg_id_aa64pfr0) || - id_aa64pfr1_mpamfrac(info->reg_id_aa64pfr1)) { + if (mpam_detect_is_enabled() && + (id_aa64pfr0_mpam(info->reg_id_aa64pfr0) || + id_aa64pfr1_mpamfrac(info->reg_id_aa64pfr1))) { taint |= check_update_ftr_reg(SYS_MPAMIDR_EL1, cpu, info->reg_mpamidr, boot->reg_mpamidr); } @@ -2317,6 +2319,9 @@ test_has_mpam(const struct arm64_cpu_capabilities *entry, int scope) !id_aa64pfr1_mpamfrac(pfr1)) return false; + if (!mpam_detect_is_enabled()) + return false; + /* Check firmware actually enabled MPAM on this cpu. */ return (read_sysreg_s(SYS_MPAM1_EL1) & MPAM_SYSREG_EN); } diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index 5ad8d8697d56c0cd98c1bbad458133e96e82fb01..7466b6066d8728247e7b1f87583f28e95d317fd8 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -461,6 +461,7 @@ static void __cpuinfo_store_cpu(struct cpuinfo_arm64 *info) __cpuinfo_store_cpu_32bit(&info->aarch32); if (IS_ENABLED(CONFIG_ARM64_MPAM) && + mpam_detect_is_enabled() && (id_aa64pfr0_mpam(info->reg_id_aa64pfr0) || id_aa64pfr1_mpamfrac(info->reg_id_aa64pfr1))) info->reg_mpamidr = read_cpuid(MPAMIDR_EL1); diff --git a/arch/arm64/kernel/mpam.c b/arch/arm64/kernel/mpam.c index 8fd9dbdc2b0110423ab238c4756b53a43097e8d3..87411609407ec0fda07789fcc069d71f7f4b478f 100644 --- a/arch/arm64/kernel/mpam.c +++ b/arch/arm64/kernel/mpam.c @@ -13,15 +13,45 @@ DEFINE_STATIC_KEY_FALSE(mpam_enabled); DEFINE_PER_CPU(u64, arm64_mpam_default); DEFINE_PER_CPU(u64, arm64_mpam_current); +static const struct midr_range mpam_disable_list[] = { + MIDR_ALL_VERSIONS(MIDR_HISI_TSV110), + { /* sentinel */ } +}; + +static bool __read_mostly mpam_detect_enabled; +static int __init mpam_setup(char *str) +{ + if (!is_midr_in_range_list(read_cpuid_id(), mpam_disable_list)) + mpam_detect_enabled = true; + + if (!strcmp(str, "acpi")) + mpam_detect_enabled = true; + + return 0; +} +early_param("mpam", mpam_setup); + +bool mpam_detect_is_enabled(void) +{ + return mpam_detect_enabled; +} + static int __init arm64_mpam_register_cpus(void) { + u16 partid_max; + u64 mpamidr; + u8 pmg_max; + if (is_kdump_kernel()) return 0; - u64 mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1); - u16 partid_max = FIELD_GET(MPAMIDR_PARTID_MAX, mpamidr); - u8 pmg_max = FIELD_GET(MPAMIDR_PMG_MAX, mpamidr); + if (!mpam_detect_is_enabled()) + return 0; + + mpamidr = read_sanitised_ftr_reg(SYS_MPAMIDR_EL1); + partid_max = FIELD_GET(MPAMIDR_PARTID_MAX, mpamidr); + pmg_max = FIELD_GET(MPAMIDR_PMG_MAX, mpamidr); return mpam_register_requestor(partid_max, pmg_max); } -arch_initcall(arm64_mpam_register_cpus) +arch_initcall(arm64_mpam_register_cpus);