[RFC PATCH v5 8/8] arm64: tlb: Set the TTL field in flush_tlb_range

From: Zhenyu Ye
Date: Tue Mar 31 2020 - 10:30:37 EST


This patch uses the cleared_* in struct mmu_gather to set the
TTL field in flush_tlb_range().

Signed-off-by: Zhenyu Ye <yezhenyu2@xxxxxxxxxx>
---
arch/arm64/include/asm/tlb.h | 39 ++++++++++++++++++++++++++++++-
arch/arm64/include/asm/tlbflush.h | 22 +++++------------
2 files changed, 44 insertions(+), 17 deletions(-)

diff --git a/arch/arm64/include/asm/tlb.h b/arch/arm64/include/asm/tlb.h
index b76df828e6b7..72b6e3763df2 100644
--- a/arch/arm64/include/asm/tlb.h
+++ b/arch/arm64/include/asm/tlb.h
@@ -21,11 +21,34 @@ static void tlb_flush(struct mmu_gather *tlb);

#include <asm-generic/tlb.h>

+/*
+ * get the tlbi levels in arm64. Default value is 0 if more than one
+ * of cleared_* is set or neither is set.
+ * Arm64 doesn't support p4ds now.
+ */
+static inline int tlb_get_level(struct mmu_gather *tlb)
+{
+ int sum = tlb->cleared_ptes + tlb->cleared_pmds +
+ tlb->cleared_puds + tlb->cleared_p4ds;
+
+ if (sum != 1)
+ return 0;
+ else if (tlb->cleared_ptes)
+ return 3;
+ else if (tlb->cleared_pmds)
+ return 2;
+ else if (tlb->cleared_puds)
+ return 1;
+
+ return 0;
+}
+
static inline void tlb_flush(struct mmu_gather *tlb)
{
struct vm_area_struct vma = TLB_FLUSH_VMA(tlb->mm, 0);
bool last_level = !tlb->freed_tables;
unsigned long stride = tlb_get_unmap_size(tlb);
+ int tlb_level = tlb_get_level(tlb);

/*
* If we're tearing down the address space then we only care about
@@ -38,7 +61,21 @@ static inline void tlb_flush(struct mmu_gather *tlb)
return;
}

- __flush_tlb_range(&vma, tlb->start, tlb->end, stride, last_level);
+ __flush_tlb_range(&vma, tlb->start, tlb->end, stride,
+ last_level, tlb_level);
+}
+
+static inline void flush_tlb_range(struct mmu_gather *tlb,
+ struct vm_area_struct *vma,
+ unsigned long start, unsigned long end)
+{
+ /*
+ * We cannot use leaf-only invalidation here, since we may be invalidating
+ * table entries as part of collapsing hugepages or moving page tables.
+ */
+ unsigned long stride = tlb_get_unmap_size(tlb);
+ int tlb_level = tlb_get_level(tlb);
+ __flush_tlb_range(vma, start, end, stride, false, tlb_level);
}

static inline void __pte_free_tlb(struct mmu_gather *tlb, pgtable_t pte,
diff --git a/arch/arm64/include/asm/tlbflush.h b/arch/arm64/include/asm/tlbflush.h
index 0b4d75a2270b..dc8e803692f8 100644
--- a/arch/arm64/include/asm/tlbflush.h
+++ b/arch/arm64/include/asm/tlbflush.h
@@ -215,7 +215,8 @@ static inline void flush_tlb_page(struct vm_area_struct *vma,

static inline void __flush_tlb_range(struct vm_area_struct *vma,
unsigned long start, unsigned long end,
- unsigned long stride, bool last_level)
+ unsigned long stride, bool last_level,
+ int tlb_level)
{
unsigned long asid = ASID(vma->vm_mm);
unsigned long addr;
@@ -237,27 +238,16 @@ static inline void __flush_tlb_range(struct vm_area_struct *vma,
dsb(ishst);
for (addr = start; addr < end; addr += stride) {
if (last_level) {
- __tlbi_level(vale1is, addr, 0);
- __tlbi_user_level(vale1is, addr, 0);
+ __tlbi_level(vale1is, addr, tlb_level);
+ __tlbi_user_level(vale1is, addr, tlb_level);
} else {
- __tlbi_level(vae1is, addr, 0);
- __tlbi_user_level(vae1is, addr, 0);
+ __tlbi_level(vae1is, addr, tlb_level);
+ __tlbi_user_level(vae1is, addr, tlb_level);
}
}
dsb(ish);
}

-static inline void flush_tlb_range(struct mmu_gather *tlb,
- struct vm_area_struct *vma,
- unsigned long start, unsigned long end)
-{
- /*
- * We cannot use leaf-only invalidation here, since we may be invalidating
- * table entries as part of collapsing hugepages or moving page tables.
- */
- __flush_tlb_range(vma, start, end, PAGE_SIZE, false);
-}
-
static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end)
{
unsigned long addr;
--
2.19.1