1 /* SPDX-License-Identifier: GPL-2.0 */ 2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4 #ifndef __ASM_CSKY_MMU_CONTEXT_H 5 #define __ASM_CSKY_MMU_CONTEXT_H 6 7 #include <asm-generic/mm_hooks.h> 8 #include <asm/setup.h> 9 #include <asm/page.h> 10 #include <asm/cacheflush.h> 11 #include <asm/tlbflush.h> 12 13 #include <linux/errno.h> 14 #include <linux/sched.h> 15 #include <abi/ckmmu.h> 16 17 #define TLBMISS_HANDLER_SETUP_PGD(pgd) \ 18 setup_pgd(__pa(pgd), false) 19 #define TLBMISS_HANDLER_SETUP_PGD_KERNEL(pgd) \ 20 setup_pgd(__pa(pgd), true) 21 22 #define cpu_context(cpu, mm) ((mm)->context.asid[cpu]) 23 #define cpu_asid(cpu, mm) (cpu_context((cpu), (mm)) & ASID_MASK) 24 #define asid_cache(cpu) (cpu_data[cpu].asid_cache) 25 26 #define ASID_FIRST_VERSION (1 << CONFIG_CPU_ASID_BITS) 27 #define ASID_INC 0x1 28 #define ASID_MASK (ASID_FIRST_VERSION - 1) 29 #define ASID_VERSION_MASK ~ASID_MASK 30 31 #define destroy_context(mm) do {} while (0) 32 #define enter_lazy_tlb(mm, tsk) do {} while (0) 33 #define deactivate_mm(tsk, mm) do {} while (0) 34 35 /* 36 * All unused by hardware upper bits will be considered 37 * as a software asid extension. 38 */ 39 static inline void 40 get_new_mmu_context(struct mm_struct *mm, unsigned long cpu) 41 { 42 unsigned long asid = asid_cache(cpu); 43 44 asid += ASID_INC; 45 if (!(asid & ASID_MASK)) { 46 flush_tlb_all(); /* start new asid cycle */ 47 if (!asid) /* fix version if needed */ 48 asid = ASID_FIRST_VERSION; 49 } 50 cpu_context(cpu, mm) = asid_cache(cpu) = asid; 51 } 52 53 /* 54 * Initialize the context related info for a new mm_struct 55 * instance. 56 */ 57 static inline int 58 init_new_context(struct task_struct *tsk, struct mm_struct *mm) 59 { 60 int i; 61 62 for_each_online_cpu(i) 63 cpu_context(i, mm) = 0; 64 return 0; 65 } 66 67 static inline void switch_mm(struct mm_struct *prev, struct mm_struct *next, 68 struct task_struct *tsk) 69 { 70 unsigned int cpu = smp_processor_id(); 71 unsigned long flags; 72 73 local_irq_save(flags); 74 /* Check if our ASID is of an older version and thus invalid */ 75 if ((cpu_context(cpu, next) ^ asid_cache(cpu)) & ASID_VERSION_MASK) 76 get_new_mmu_context(next, cpu); 77 write_mmu_entryhi(cpu_asid(cpu, next)); 78 TLBMISS_HANDLER_SETUP_PGD(next->pgd); 79 80 /* 81 * Mark current->active_mm as not "active" anymore. 82 * We don't want to mislead possible IPI tlb flush routines. 83 */ 84 cpumask_clear_cpu(cpu, mm_cpumask(prev)); 85 cpumask_set_cpu(cpu, mm_cpumask(next)); 86 87 local_irq_restore(flags); 88 } 89 90 /* 91 * After we have set current->mm to a new value, this activates 92 * the context for the new mm so we see the new mappings. 93 */ 94 static inline void 95 activate_mm(struct mm_struct *prev, struct mm_struct *next) 96 { 97 unsigned long flags; 98 int cpu = smp_processor_id(); 99 100 local_irq_save(flags); 101 102 /* Unconditionally get a new ASID. */ 103 get_new_mmu_context(next, cpu); 104 105 write_mmu_entryhi(cpu_asid(cpu, next)); 106 TLBMISS_HANDLER_SETUP_PGD(next->pgd); 107 108 /* mark mmu ownership change */ 109 cpumask_clear_cpu(cpu, mm_cpumask(prev)); 110 cpumask_set_cpu(cpu, mm_cpumask(next)); 111 112 local_irq_restore(flags); 113 } 114 115 /* 116 * If mm is currently active_mm, we can't really drop it. Instead, 117 * we will get a new one for it. 118 */ 119 static inline void 120 drop_mmu_context(struct mm_struct *mm, unsigned int cpu) 121 { 122 unsigned long flags; 123 124 local_irq_save(flags); 125 126 if (cpumask_test_cpu(cpu, mm_cpumask(mm))) { 127 get_new_mmu_context(mm, cpu); 128 write_mmu_entryhi(cpu_asid(cpu, mm)); 129 } else { 130 /* will get a new context next time */ 131 cpu_context(cpu, mm) = 0; 132 } 133 134 local_irq_restore(flags); 135 } 136 137 #endif /* __ASM_CSKY_MMU_CONTEXT_H */ 138