In RISC-V, tlb flush happens via SBI which is expensive.
If the target cpumask contains a local hartid, some cost
can be saved by issuing a local tlb flush as we do that
in OpenSBI anyways.

Signed-off-by: Atish Patra <atish.pa...@wdc.com>
---
 arch/riscv/include/asm/tlbflush.h | 33 +++++++++++++++++++++++++++----
 1 file changed, 29 insertions(+), 4 deletions(-)

diff --git a/arch/riscv/include/asm/tlbflush.h 
b/arch/riscv/include/asm/tlbflush.h
index 687dd19735a7..b32ba4fa5888 100644
--- a/arch/riscv/include/asm/tlbflush.h
+++ b/arch/riscv/include/asm/tlbflush.h
@@ -8,6 +8,7 @@
 #define _ASM_RISCV_TLBFLUSH_H
 
 #include <linux/mm_types.h>
+#include <linux/sched.h>
 #include <asm/smp.h>
 
 /*
@@ -46,14 +47,38 @@ static inline void remote_sfence_vma(struct cpumask *cmask, 
unsigned long start,
                                     unsigned long size)
 {
        struct cpumask hmask;
+       struct cpumask tmask;
+       int cpuid = smp_processor_id();
 
        cpumask_clear(&hmask);
-       riscv_cpuid_to_hartid_mask(cmask, &hmask);
-       sbi_remote_sfence_vma(hmask.bits, start, size);
+       cpumask_clear(&tmask);
+
+       if (cmask)
+               cpumask_copy(&tmask, cmask);
+       else
+               cpumask_copy(&tmask, cpu_online_mask);
+
+       if (cpumask_test_cpu(cpuid, &tmask)) {
+               /* Save trap cost by issuing a local tlb flush here */
+               if ((start == 0 && size == -1) || (size > PAGE_SIZE))
+                       local_flush_tlb_all();
+               else if (size == PAGE_SIZE)
+                       local_flush_tlb_page(start);
+               cpumask_clear_cpu(cpuid, &tmask);
+       } else if (cpumask_empty(&tmask)) {
+               /* cpumask is empty. So just do a local flush */
+               local_flush_tlb_all();
+               return;
+       }
+
+       if (!cpumask_empty(&tmask)) {
+               riscv_cpuid_to_hartid_mask(&tmask, &hmask);
+               sbi_remote_sfence_vma(hmask.bits, start, size);
+       }
 }
 
-#define flush_tlb_all() sbi_remote_sfence_vma(NULL, 0, -1)
-#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, 0)
+#define flush_tlb_all() remote_sfence_vma(NULL, 0, -1)
+#define flush_tlb_page(vma, addr) flush_tlb_range(vma, addr, (addr) + 
PAGE_SIZE)
 #define flush_tlb_range(vma, start, end) \
        remote_sfence_vma(mm_cpumask((vma)->vm_mm), start, (end) - (start))
 #define flush_tlb_mm(mm) \
-- 
2.21.0

Reply via email to