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

[XEN][RESEND][PATCH 2/3] xen/arm: optimize stage-1,2 combined TLBI in presence of FEAT_nTLBPA



From: Haseeb Ashraf <haseeb.ashraf@xxxxxxxxxxx>

FEAT_nTLBPA guarantees that intermediate caching of translation table
walks does not retain non-coherent cached copies of previously valid
translation table entries since the last completed applicable TLBI.

When FEAT_nTLBPA is present, a stage-2 invalidation no longer needs to
be paired with an additional stage-1 invalidation solely to discard
such side effects. Use this to avoid redundant stage-1 invalidation in
the combined guest TLBI paths.

Update the stage-1-only guest TLBI helpers so that they become no-ops
when FEAT_nTLBPA is present. This allows existing call sites that
conservatively issue stage-1 invalidation after stage-2 invalidation to
benefit without further restructuring.

Also update the Arm64 IPA-based invalidation helper so that:
  - stage-2 invalidation by IPA is performed explicitly,
  - stage-1 invalidation is issued separately only when FEAT_nTLBPA is
    absent,
  - completion of the broadcast TLBI sequence remains explicit.

This makes the architectural intent clearer and avoids redundant
invalidations on systems that implement FEAT_nTLBPA.

Suggested-by: Mohamed Mediouni <mohamed@xxxxxxxxxxxxxxxx>
Signed-off-by: Haseeb Ashraf <haseeb.ashraf@xxxxxxxxxxx>

Changes in v4:
- Reworked the Arm64 IPA-based invalidation helper so that stage-2,
  optional stage-1, and final TLBI completion are expressed
  separately and explicitly.
- Simplified the FEAT_nTLBPA optimization by reusing the explicit TLBI
  completion helper instead of open-coding a special final IPA TLBI
  sequence.
- Refined comments and commit message wording.

Changes in v3:
- This commit has no functional change in v3, only rebasing changes
  due to updates in commit-1.

Changes in v2:
- This commit is implemented in v2 and is splitted from commit-1 in
  v1. This is implemented by using CPU capability.
---
 xen/arch/arm/cpufeature.c                 | 19 ++++++++++
 xen/arch/arm/include/asm/arm32/flushtlb.h | 14 ++++----
 xen/arch/arm/include/asm/arm64/flushtlb.h | 44 +++++++++++++++++++----
 xen/arch/arm/include/asm/cpufeature.h     | 24 +++++++++++--
 xen/arch/arm/include/asm/processor.h      |  7 ++++
 5 files changed, 93 insertions(+), 15 deletions(-)

diff --git a/xen/arch/arm/cpufeature.c b/xen/arch/arm/cpufeature.c
index 94d14fb6a9..86720c10a3 100644
--- a/xen/arch/arm/cpufeature.c
+++ b/xen/arch/arm/cpufeature.c
@@ -17,7 +17,19 @@ DECLARE_BITMAP(cpu_hwcaps, ARM_NCAPS);
 
 struct cpuinfo_arm __read_mostly domain_cpuinfo;
 
+#ifdef CONFIG_ARM_32
+static bool has_ntlbpa(const struct arm_cpu_capabilities *entry)
+{
+    return system_cpuinfo.mm32.ntlbpa == MM32_NTLBPA_SUPPORT_IMP;
+}
+#endif
+
 #ifdef CONFIG_ARM_64
+static bool has_ntlbpa(const struct arm_cpu_capabilities *entry)
+{
+    return system_cpuinfo.mm64.ntlbpa == MM64_NTLBPA_SUPPORT_IMP;
+}
+
 static bool has_sb_instruction(const struct arm_cpu_capabilities *entry)
 {
     return system_cpuinfo.isa64.sb;
@@ -25,6 +37,13 @@ static bool has_sb_instruction(const struct 
arm_cpu_capabilities *entry)
 #endif
 
 static const struct arm_cpu_capabilities arm_features[] = {
+#if defined(CONFIG_ARM_32) || defined(CONFIG_ARM_64)
+    {
+        .desc = "Intermediate caching of translation table walks (nTLBPA)",
+        .capability = ARM_HAS_NTLBPA,
+        .matches = has_ntlbpa,
+    },
+#endif
 #ifdef CONFIG_ARM_64
     {
         .desc = "Speculation barrier instruction (SB)",
diff --git a/xen/arch/arm/include/asm/arm32/flushtlb.h 
b/xen/arch/arm/include/asm/arm32/flushtlb.h
index 1497f16ba5..30df161323 100644
--- a/xen/arch/arm/include/asm/arm32/flushtlb.h
+++ b/xen/arch/arm/include/asm/arm32/flushtlb.h
@@ -49,8 +49,8 @@ TLB_HELPER(flush_xen_tlb_local, TLBIALLH, nsh)
  * Flush TLB of local processor. Use when flush for only stage-1 is intended.
  *
  * The following function should be used where intention is to clear only
- * stage-1 TLBs. This would be helpful in future in identifying which stage-1
- * TLB flushes can be skipped such as in present of FEAT_nTLBPA.
+ * stage-1 TLBs. This would be helpful in identifying which stage-1 TLB flushes
+ * can be skipped such as in present of FEAT_nTLBPA.
  */
 static inline void flush_guest_tlb_s1_local(void)
 {
@@ -60,7 +60,8 @@ static inline void flush_guest_tlb_s1_local(void)
      *
      * See ARMv8 (DDI 0487L.b): G5-11698 Table G5-23.
      */
-    return flush_guest_tlb_local();
+    if ( !cpus_have_const_cap(ARM_HAS_NTLBPA) )
+        flush_guest_tlb_local();
 }
 
 /*
@@ -68,8 +69,8 @@ static inline void flush_guest_tlb_s1_local(void)
  * stage-1 is intended.
  *
  * The following function should be used where intention is to clear only
- * stage-1 TLBs. This would be helpful in future in identifying which stage-1
- * TLB flushes can be skipped such as in present of FEAT_nTLBPA.
+ * stage-1 TLBs. This would be helpful in identifying which stage-1 TLB flushes
+ * can be skipped such as in present of FEAT_nTLBPA.
  */
 static inline void flush_guest_tlb_s1(void)
 {
@@ -79,7 +80,8 @@ static inline void flush_guest_tlb_s1(void)
      *
      * See ARMv8 (DDI 0487L.b): G5-11698 Table G5-23.
      */
-    return flush_guest_tlb();
+    if ( !cpus_have_const_cap(ARM_HAS_NTLBPA) )
+        flush_guest_tlb();
 }
 
 /* Flush TLB of local processor for address va. */
diff --git a/xen/arch/arm/include/asm/arm64/flushtlb.h 
b/xen/arch/arm/include/asm/arm64/flushtlb.h
index cbe2a0da57..de266b0e11 100644
--- a/xen/arch/arm/include/asm/arm64/flushtlb.h
+++ b/xen/arch/arm/include/asm/arm64/flushtlb.h
@@ -63,6 +63,36 @@ static inline void name(void)                         \
         : : : "memory"); \
 }
 
+#define TLB_HELPER_NTLBPA_LOCAL(name, tlbop)     \
+static inline void name(void)                    \
+{                                                \
+    if ( !cpus_have_const_cap(ARM_HAS_NTLBPA) )  \
+        asm_inline volatile (                    \
+            "dsb  nshst;"                        \
+            "tlbi "  # tlbop  ";"                \
+            "dsb  nsh;"                          \
+            "isb;"                               \
+            : : : "memory");                     \
+}
+
+#define TLB_HELPER_NTLBPA(name, tlbop)                \
+static inline void name(void)                         \
+{                                                     \
+    if ( !cpus_have_const_cap(ARM_HAS_NTLBPA) )       \
+        asm_inline volatile (                         \
+            "dsb  ishst;"                             \
+            "tlbi "  # tlbop  ";"                     \
+            ALTERNATIVE(                              \
+                "nop; nop;",                          \
+                "dsb  ish;"                           \
+                "tlbi vale2is, xzr;",                 \
+                ARM64_WORKAROUND_REPEAT_TLBI,         \
+                CONFIG_ARM64_WORKAROUND_REPEAT_TLBI)  \
+            "dsb  ish;"                               \
+            "isb;"                                    \
+            : : : "memory");                          \
+}
+
 /* Flush local TLBs, current VMID only. */
 TLB_HELPER_LOCAL(flush_guest_tlb_local, vmalls12e1)
 
@@ -70,10 +100,10 @@ TLB_HELPER_LOCAL(flush_guest_tlb_local, vmalls12e1)
 TLB_HELPER(flush_guest_tlb, vmalls12e1is)
 
 /* Flush local TLBs, current VMID, stage-1 only */
-TLB_HELPER(flush_guest_tlb_s1_local, vmalle1, nsh)
+TLB_HELPER_NTLBPA_LOCAL(flush_guest_tlb_s1_local, vmalle1)
 
 /* Flush innershareable TLBs, current VMID, stage-1 only */
-TLB_HELPER(flush_guest_tlb_s1, vmalle1is, ish)
+TLB_HELPER_NTLBPA(flush_guest_tlb_s1, vmalle1is)
 
 /* Flush local TLBs, all VMIDs, non-hypervisor mode */
 TLB_HELPER_LOCAL(flush_all_guests_tlb_local, alle1)
@@ -86,6 +116,8 @@ TLB_HELPER_LOCAL(flush_xen_tlb_local, alle2)
 
 #undef TLB_HELPER_LOCAL
 #undef TLB_HELPER
+#undef TLB_HELPER_NTLBPA_LOCAL
+#undef TLB_HELPER_NTLBPA
 
 /*
  * FLush TLB by VA. This will likely be used in a loop, so the caller
@@ -169,11 +201,11 @@ static inline void flush_guest_tlb_range_ipa(paddr_t ipa, 
unsigned long size)
     }
 
     /*
-     * Invalidate stage-1 entries for the current VMID as well. Keep this
-     * separate from completion of the broadcast TLBI sequence so that the
-     * final barriers/workaround are explicit.
+     * Without FEAT_nTLBPA, invalidate corresponding stage-1 side effects
+     * separately. Completion of the broadcast TLBI sequence remains explicit.
      */
-    asm_inline volatile("tlbi vmalle1is" : : : "memory");
+    if ( !cpus_have_const_cap(ARM_HAS_NTLBPA) )
+        asm_inline volatile("tlbi vmalle1is" : : : "memory");
 
     tlbi_complete_broadcast();
 }
diff --git a/xen/arch/arm/include/asm/cpufeature.h 
b/xen/arch/arm/include/asm/cpufeature.h
index bf902a3970..3e56dd27ef 100644
--- a/xen/arch/arm/include/asm/cpufeature.h
+++ b/xen/arch/arm/include/asm/cpufeature.h
@@ -76,8 +76,9 @@
 #define ARM_WORKAROUND_BHB_SMCC_3 15
 #define ARM_HAS_SB 16
 #define ARM64_WORKAROUND_1508412 17
+#define ARM_HAS_NTLBPA 18
 
-#define ARM_NCAPS           18
+#define ARM_NCAPS           19
 
 #ifndef __ASSEMBLER__
 
@@ -276,7 +277,8 @@ struct cpuinfo_arm {
             unsigned long ets:4;
             unsigned long __res2:4;
             unsigned long afp:4;
-            unsigned long __res3:12;
+            unsigned long ntlbpa:4;
+            unsigned long __res3:8;
             unsigned long ecbhb:4;
 
             /* MMFR2 */
@@ -437,8 +439,24 @@ struct cpuinfo_arm {
         register_t bits[1];
     } aux32;
 
-    struct {
+    union {
         register_t bits[6];
+        struct {
+            /* MMFR0 */
+            unsigned long __res0:32;
+            /* MMFR1 */
+            unsigned long __res1:32;
+            /* MMFR2 */
+            unsigned long __res2:32;
+            /* MMFR3 */
+            unsigned long __res3:32;
+            /* MMFR4 */
+            unsigned long __res4:32;
+            /* MMFR5 */
+            unsigned long __res5:4;
+            unsigned long ntlbpa:4;
+            unsigned long __res6:24;
+        };
     } mm32;
 
     struct {
diff --git a/xen/arch/arm/include/asm/processor.h 
b/xen/arch/arm/include/asm/processor.h
index a3753c317f..dbf9471a7a 100644
--- a/xen/arch/arm/include/asm/processor.h
+++ b/xen/arch/arm/include/asm/processor.h
@@ -484,9 +484,16 @@
 /* FSR long format */
 #define FSRL_STATUS_DEBUG       (_AC(0x22,UL)<<0)
 
+#ifdef CONFIG_ARM_32
+#define MM32_NTLBPA_SUPPORT_NI      0x0
+#define MM32_NTLBPA_SUPPORT_IMP     0x1
+#endif
+
 #ifdef CONFIG_ARM_64
 #define MM64_VMID_8_BITS_SUPPORT    0x0
 #define MM64_VMID_16_BITS_SUPPORT   0x2
+#define MM64_NTLBPA_SUPPORT_NI      0x0
+#define MM64_NTLBPA_SUPPORT_IMP     0x1
 #endif
 
 #define MM64_MSA_PMSA_SUPPORT       0xf
-- 
2.43.0




 


Rackspace

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