[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
lmpx.com only provides a reader for public news (NNTP) servers. It is not affiliated with the servers or forums shown here and is not responsible for the content of articles, which is written by their respective authors.