csky: Use generic asid algorithm to implement switch_mm
authorGuo Ren <ren_guo@c-sky.com>
Tue, 18 Jun 2019 12:33:32 +0000 (20:33 +0800)
committerGuo Ren <ren_guo@c-sky.com>
Fri, 19 Jul 2019 06:21:36 +0000 (14:21 +0800)
Use linux generic asid/vmid algorithm to implement csky
switch_mm function. The algorithm is from arm and it could
work with SMP system. It'll help reduce tlb flush for
switch_mm in task/vm switch.

Signed-off-by: Guo Ren <ren_guo@c-sky.com>
Cc: Arnd Bergmann <arnd@arndb.de>
arch/csky/abiv1/inc/abi/ckmmu.h
arch/csky/abiv2/inc/abi/ckmmu.h
arch/csky/include/asm/mmu.h
arch/csky/include/asm/mmu_context.h
arch/csky/mm/Makefile
arch/csky/mm/context.c [new file with mode: 0644]

index 81f37715c0d26d3d9ffa73e7f4ba4f970f37b601..ba8eb58708351a8296d64268408be9a191103e0c 100644 (file)
@@ -78,6 +78,12 @@ static inline void tlb_invalid_all(void)
        cpwcr("cpcr8", 0x04000000);
 }
 
+
+static inline void local_tlb_invalid_all(void)
+{
+       tlb_invalid_all();
+}
+
 static inline void tlb_invalid_indexed(void)
 {
        cpwcr("cpcr8", 0x02000000);
index e4480e6bc3b3d3bf2d6902fcfcb4e0c7d04ca1b4..73ded7c72482b8355372201e2a55f35c5cc123b1 100644 (file)
@@ -85,6 +85,16 @@ static inline void tlb_invalid_all(void)
 #endif
 }
 
+static inline void local_tlb_invalid_all(void)
+{
+#ifdef CONFIG_CPU_HAS_TLBI
+       asm volatile("tlbi.all\n":::"memory");
+       sync_is();
+#else
+       tlb_invalid_all();
+#endif
+}
+
 static inline void tlb_invalid_indexed(void)
 {
        mtcr("cr<8, 15>", 0x02000000);
index 06f509ae09b026110fab2f91c6d156948a249686..b382a14ea4ec72535393b4a6962b1f1020ab0b7e 100644 (file)
@@ -5,6 +5,7 @@
 #define __ASM_CSKY_MMU_H
 
 typedef struct {
+       atomic64_t      asid;
        void *vdso;
 } mm_context_t;
 
index 86dde481df76e84f4ad6b8c1af427afe9ea3dacd..0285b0ad18b6f2bce9276396461f9a1ffc2ed2f2 100644 (file)
 #define TLBMISS_HANDLER_SETUP_PGD_KERNEL(pgd) \
        setup_pgd(__pa(pgd), true)
 
-#define init_new_context(tsk,mm)       0
+#define ASID_MASK              ((1 << CONFIG_CPU_ASID_BITS) - 1)
+#define cpu_asid(mm)           (atomic64_read(&mm->context.asid) & ASID_MASK)
+
+#define init_new_context(tsk,mm)       ({ atomic64_set(&(mm)->context.asid, 0); 0; })
 #define activate_mm(prev,next)         switch_mm(prev, next, current)
 
 #define destroy_context(mm)            do {} while (0)
 #define enter_lazy_tlb(mm, tsk)                do {} while (0)
 #define deactivate_mm(tsk, mm)         do {} while (0)
 
+void check_and_switch_context(struct mm_struct *mm, unsigned int cpu);
+
 static inline void
 switch_mm(struct mm_struct *prev, struct mm_struct *next,
          struct task_struct *tsk)
 {
+       unsigned int cpu = smp_processor_id();
+
        if (prev != next)
-               tlb_invalid_all();
+               check_and_switch_context(next, cpu);
 
        TLBMISS_HANDLER_SETUP_PGD(next->pgd);
+       write_mmu_entryhi(next->context.asid.counter);
 }
 #endif /* __ASM_CSKY_MMU_CONTEXT_H */
index d3d564e5da616f97be42a86ec2bbd0b13f5090ab..c94ef648109865e5662edeb1a61c9685426340fa 100644 (file)
@@ -13,3 +13,4 @@ obj-y +=                      ioremap.o
 obj-y +=                       syscache.o
 obj-y +=                       tlb.o
 obj-y +=                       asid.o
+obj-y +=                       context.o
diff --git a/arch/csky/mm/context.c b/arch/csky/mm/context.c
new file mode 100644 (file)
index 0000000..0d95bdd
--- /dev/null
@@ -0,0 +1,46 @@
+// SPDX-License-Identifier: GPL-2.0
+// Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd.
+
+#include <linux/bitops.h>
+#include <linux/sched.h>
+#include <linux/slab.h>
+#include <linux/mm.h>
+
+#include <asm/asid.h>
+#include <asm/mmu_context.h>
+#include <asm/smp.h>
+#include <asm/tlbflush.h>
+
+static DEFINE_PER_CPU(atomic64_t, active_asids);
+static DEFINE_PER_CPU(u64, reserved_asids);
+
+struct asid_info asid_info;
+
+void check_and_switch_context(struct mm_struct *mm, unsigned int cpu)
+{
+       asid_check_context(&asid_info, &mm->context.asid, cpu, mm);
+}
+
+static void asid_flush_cpu_ctxt(void)
+{
+       local_tlb_invalid_all();
+}
+
+static int asids_init(void)
+{
+       BUG_ON(((1 << CONFIG_CPU_ASID_BITS) - 1) <= num_possible_cpus());
+
+       if (asid_allocator_init(&asid_info, CONFIG_CPU_ASID_BITS, 1,
+                               asid_flush_cpu_ctxt))
+               panic("Unable to initialize ASID allocator for %lu ASIDs\n",
+                     NUM_ASIDS(&asid_info));
+
+       asid_info.active = &active_asids;
+       asid_info.reserved = &reserved_asids;
+
+       pr_info("ASID allocator initialised with %lu entries\n",
+               NUM_CTXT_ASIDS(&asid_info));
+
+       return 0;
+}
+early_initcall(asids_init);