[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[XEN][RESEND][PATCH 3/3] xen/arm32: use IPA-based TLBI when supported with FEAT_nTLBPA



From: Haseeb Ashraf <haseeb.ashraf@xxxxxxxxxxx>

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 <julien@xxxxxxx>
Signed-off-by: Haseeb Ashraf <haseeb.ashraf@xxxxxxxxxxx>

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




 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.