diff mbox series

[3/3] arm64: cpufeature: workaround AmpereOne FEAT_BBM level 2

Message ID 20241118181711.962576-4-yang@os.amperecomputing.com (mailing list archive)
State New
Headers show
Series arm64: support FEAT_BBM level 2 and large block mapping when rodata=full | expand

Commit Message

Yang Shi Nov. 18, 2024, 6:16 p.m. UTC
FEAT_BBM level 2 is not advertised on AmpereOne because of a bug when
collapsing stage 2 mappings from smaller to larger translations.  That
doesn't impact splitting stage 1 mappings (whether stage 2 is enabled or
not), so workaround it by detecting CPUID.

Signed-off-by: Yang Shi <yang@os.amperecomputing.com>
---
 arch/arm64/include/asm/cpufeature.h | 11 ++++++++++-
 1 file changed, 10 insertions(+), 1 deletion(-)

Comments

Christoph Lameter (Ampere) Nov. 18, 2024, 6:33 p.m. UTC | #1
On Mon, 18 Nov 2024, Yang Shi wrote:

> FEAT_BBM level 2 is not advertised on AmpereOne because of a bug when
> collapsing stage 2 mappings from smaller to larger translations.  That
> doesn't impact splitting stage 1 mappings (whether stage 2 is enabled or
> not), so workaround it by detecting CPUID.


Would be better to have a bblmv2_split_available() function that only
checks for the splitting capability.

If more code is added that uses the so far unused collapsing features
also included in the BBML2 feature set then that will break on AmpereOne.

bbml2_split_available() could call bbml2_available() and check the ampere
errata when false.

Should work fine for now.

Reviewed-by: Christoph Lameter <cl@linux.com>
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index c7ca5f9f88bb..d9b20eb43d31 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -847,10 +847,19 @@  static inline bool bbmlv2_available(void)
 {
 	u64 mmfr2;
 	u32 bbm;
+	static const struct midr_range ampereone[] = {
+		MIDR_ALL_VERSIONS(MIDR_AMPERE1),
+		MIDR_ALL_VERSIONS(MIDR_AMPERE1A),
+		{}
+	};
 
 	mmfr2 = read_sanitised_ftr_reg(SYS_ID_AA64MMFR2_EL1);
 	bbm = cpuid_feature_extract_unsigned_field(mmfr2, ID_AA64MMFR2_EL1_BBM_SHIFT);
-	return bbm == ID_AA64MMFR2_EL1_BBM_2;
+	if ((bbm == ID_AA64MMFR2_EL1_BBM_2) ||
+	    is_midr_in_range_list(read_cpuid_id(), ampereone))
+		return true;
+
+	return false;
 }
 
 int do_emulate_mrs(struct pt_regs *regs, u32 sys_reg, u32 rt);