[XEN][RESEND][PATCH 3/3] xen/arm32: use IPA-based TLBI when supported with FEAT_nTLBPA
Haseeb Ashraf <[email protected]>
| Newsgroups | org.xenproject.lists.xen-devel |
|---|---|
| Message-ID | <d072f06ddbe9960b20d454809cdcdcfd294532f9.1784619778.git.haseeb.ashraf@siemens.com> |
From: Haseeb Ashraf <[email protected]> Arm32 provides TLBI-by-IPA instructions on CPUs that implement the relevant stage-2 invalidation support. Detect this as a CPU capability and use it to perform IPA-based invalidation in the p2m range flush helper. On Arm32, however, IPA-based stage-2 invalidation is only useful when FEAT_nTLBPA is also present. Without FEAT_nTLBPA, a stage-2 invalidation may still require discarding associated stage-1 side effects, and Arm32 does not provide a separate stage-1 guest TLBI that Xen can use here. In that case, falling back to the existing full guest flush remains the correct approach. Therefore, enable Arm32 IPA-based invalidation only when both: - TLBI-by-IPA is supported, and - FEAT_nTLBPA is present. As on Arm64, the helper bounds the per-page invalidation loop with a 256MB cutoff and falls back to a full guest flush for larger ranges. For Arm32 this threshold is used as a conservative practical limit, reusing the Arm64 cutoff, rather than as an Arm32-specific tuned value. Suggested-by: Julien Grall <[email protected]> Signed-off-by: Haseeb Ashraf <[email protected]> Changes in v4: - Clarified that Arm32 IPA-based TLBI is only enabled when both TLBI-by-IPA support and FEAT_nTLBPA are present. - Clarified that the 256MB threshold is reused as a conservative practical cutoff and is not based on Arm32-specific measurements. - Refined comments and commit message wording. Changes in v3: - There are no functional changes in this version. There are minor code updates and comment updates as per the feedback on v2. - The cpregs are defined in order as per Coprocessor-> CRn-> Opcode 1 -> CRm-> Opcode 2. - Added comment to explain why IPA-based TLBI is added only in presence of FEAT_nTLBPA. - Replaced `goto default_tlbi` with if...else. - Removed extra definitions of MM32_UNITLB_* macros which were not being used. Changes in v2: - This commit is implemented in v2 as per the feedback to implement IPA-based TLBI for Arm32 in addition to Arm64. --- xen/arch/arm/cpufeature.c | 12 ++++++ xen/arch/arm/include/asm/arm32/flushtlb.h | 47 ++++++++++++++++++++--- xen/arch/arm/include/asm/cpregs.h | 1 + xen/arch/arm/include/asm/cpufeature.h | 15 +++++--- xen/arch/arm/include/asm/processor.h | 3 ++ 5 files changed, 67 insertions(+), 11 deletions(-) diff --git a/xen/arch/arm/cpufeature.c b/xen/arch/arm/cpufeature.c index 86720c10a3..9ca449a551 100644 --- a/xen/arch/arm/cpufeature.c +++ b/xen/arch/arm/cpufeature.c @@ -18,6 +18,11 @@ DECLARE_BITMAP(cpu_hwcaps, ARM_NCAPS); struct cpuinfo_arm __read_mostly domain_cpuinfo; #ifdef CONFIG_ARM_32 +static bool has_tlb_ipa_instruction(const struct arm_cpu_capabilities *entry) +{ + return system_cpuinfo.mm32.unitlb == MM32_UNITLB_BY_IPA; +} + static bool has_ntlbpa(const struct arm_cpu_capabilities *entry) { return system_cpuinfo.mm32.ntlbpa == MM32_NTLBPA_SUPPORT_IMP; @@ -37,6 +42,13 @@ static bool has_sb_instruction(const struct arm_cpu_capabilities *entry) #endif static const struct arm_cpu_capabilities arm_features[] = { +#ifdef CONFIG_ARM_32 + { + .desc = "IPA-based TLB Invalidation", + .capability = ARM32_HAS_TLB_IPA, + .matches = has_tlb_ipa_instruction, + }, +#endif #if defined(CONFIG_ARM_32) || defined(CONFIG_ARM_64) { .desc = "Intermediate caching of translation table walks (nTLBPA)", diff --git a/xen/arch/arm/include/asm/arm32/flushtlb.h b/xen/arch/arm/include/asm/arm32/flushtlb.h index 30df161323..1db6b8410e 100644 --- a/xen/arch/arm/include/asm/arm32/flushtlb.h +++ b/xen/arch/arm/include/asm/arm32/flushtlb.h @@ -1,6 +1,8 @@ #ifndef __ASM_ARM_ARM32_FLUSHTLB_H__ #define __ASM_ARM_ARM32_FLUSHTLB_H__ +#include <xen/sizes.h> /* For SZ_* macros. */ + /* * Every invalidation operation use the following patterns: * @@ -107,12 +109,47 @@ static inline void flush_guest_tlb_range_ipa(paddr_t ipa, unsigned long size) { /* - * Following can invalidate both stage-1 and stage-2 TLBs depending upon - * the execution mode. - * - * See ARMv8 (DDI 0487L.b): G5-11698 Table G5-23. + * IPA-based stage-2 invalidation is only useful when FEAT_nTLBPA is + * present. Without FEAT_nTLBPA, invalidating stage-2 alone may still + * require discarding associated stage-1 side effects, and Arm32 does not + * provide a separate guest stage-1 TLBI for that case. */ - flush_guest_tlb(); + if ( cpus_have_const_cap(ARM_HAS_NTLBPA) && + cpus_have_const_cap(ARM32_HAS_TLB_IPA) ) + { + /* + * If the IPA range is too large, fall back to a full guest flush + * rather than issuing a long per-page TLBI sequence. Reuse the same + * practical cutoff as Arm64. + */ + if ( size > SZ_256M ) + flush_guest_tlb(); + else + { + paddr_t end = ipa + size; + + dsb(ishst); /* Ensure prior page-tables updates have completed */ + while ( ipa < end ) + { + /* Flush stage-2 TLBs for this IPA. */ + asm volatile ( STORE_CP32(0, TLBIIPAS2IS) + : : "r" (ipa >> PAGE_SHIFT) : "memory" ); + ipa += PAGE_SIZE; + } + dsb(ish); + isb(); + } + } + else + { + /* + * Following can invalidate both stage-1 and stage-2 TLBs depending + * upon the execution mode. + * + * See ARMv8 (DDI 0487L.b): G5-11698 Table G5-23. + */ + flush_guest_tlb(); + } } #endif /* __ASM_ARM_ARM32_FLUSHTLB_H__ */ diff --git a/xen/arch/arm/include/asm/cpregs.h b/xen/arch/arm/include/asm/cpregs.h index a7503a190f..26b5c08d0e 100644 --- a/xen/arch/arm/include/asm/cpregs.h +++ b/xen/arch/arm/include/asm/cpregs.h @@ -223,6 +223,7 @@ #define TLBIMVA p15,0,c8,c7,1 /* invalidate unified TLB entry by MVA */ #define TLBIASID p15,0,c8,c7,2 /* invalid unified TLB by ASID match */ #define TLBIMVAA p15,0,c8,c7,3 /* invalidate unified TLB entries by MVA all ASID */ +#define TLBIIPAS2IS p15,4,c8,c0,1 /* Invalidate unified TLB entry for stage 2 by IPA inner shareable */ #define TLBIALLHIS p15,4,c8,c3,0 /* Invalidate Entire Hyp. Unified TLB inner shareable */ #define TLBIMVAHIS p15,4,c8,c3,1 /* Invalidate Unified Hyp. TLB by MVA inner shareable */ #define TLBIALLNSNHIS p15,4,c8,c3,4 /* Invalidate Entire Non-Secure Non-Hyp. Unified TLB inner shareable */ diff --git a/xen/arch/arm/include/asm/cpufeature.h b/xen/arch/arm/include/asm/cpufeature.h index 3e56dd27ef..09a516fe49 100644 --- a/xen/arch/arm/include/asm/cpufeature.h +++ b/xen/arch/arm/include/asm/cpufeature.h @@ -77,8 +77,9 @@ #define ARM_HAS_SB 16 #define ARM64_WORKAROUND_1508412 17 #define ARM_HAS_NTLBPA 18 +#define ARM32_HAS_TLB_IPA 19 -#define ARM_NCAPS 19 +#define ARM_NCAPS 20 #ifndef __ASSEMBLER__ @@ -447,15 +448,17 @@ struct cpuinfo_arm { /* MMFR1 */ unsigned long __res1:32; /* MMFR2 */ - unsigned long __res2:32; + unsigned long __res2:16; + unsigned long unitlb:4; + unsigned long __res3:12; /* MMFR3 */ - unsigned long __res3:32; - /* MMFR4 */ unsigned long __res4:32; + /* MMFR4 */ + unsigned long __res5:32; /* MMFR5 */ - unsigned long __res5:4; + unsigned long __res6:4; unsigned long ntlbpa:4; - unsigned long __res6:24; + unsigned long __res7:24; }; } mm32; diff --git a/xen/arch/arm/include/asm/processor.h b/xen/arch/arm/include/asm/processor.h index dbf9471a7a..0c47225de0 100644 --- a/xen/arch/arm/include/asm/processor.h +++ b/xen/arch/arm/include/asm/processor.h @@ -485,6 +485,9 @@ #define FSRL_STATUS_DEBUG (_AC(0x22,UL)<<0) #ifdef CONFIG_ARM_32 +#define MM32_UNITLB_NI 0x0 +#define MM32_UNITLB_BY_IPA 0x6 + #define MM32_NTLBPA_SUPPORT_NI 0x0 #define MM32_NTLBPA_SUPPORT_IMP 0x1 #endif -- 2.43.0