1 // SPDX-License-Identifier: GPL-2.0 2 // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3 4 #include <linux/init.h> 5 #include <linux/mm.h> 6 #include <linux/module.h> 7 #include <linux/sched.h> 8 9 #include <asm/mmu_context.h> 10 #include <asm/setup.h> 11 12 /* 13 * One C-SKY MMU TLB entry contain two PFN/page entry, ie: 14 * 1VPN -> 2PFN 15 */ 16 #define TLB_ENTRY_SIZE (PAGE_SIZE * 2) 17 #define TLB_ENTRY_SIZE_MASK (PAGE_MASK << 1) 18 19 void flush_tlb_all(void) 20 { 21 tlb_invalid_all(); 22 } 23 24 void flush_tlb_mm(struct mm_struct *mm) 25 { 26 #ifdef CONFIG_CPU_HAS_TLBI 27 sync_is(); 28 asm volatile( 29 "tlbi.asids %0 \n" 30 "sync.i \n" 31 : 32 : "r" (cpu_asid(mm)) 33 : "memory"); 34 #else 35 tlb_invalid_all(); 36 #endif 37 } 38 39 /* 40 * MMU operation regs only could invalid tlb entry in jtlb and we 41 * need change asid field to invalid I-utlb & D-utlb. 42 */ 43 #ifndef CONFIG_CPU_HAS_TLBI 44 #define restore_asid_inv_utlb(oldpid, newpid) \ 45 do { \ 46 if (oldpid == newpid) \ 47 write_mmu_entryhi(oldpid + 1); \ 48 write_mmu_entryhi(oldpid); \ 49 } while (0) 50 #endif 51 52 void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 53 unsigned long end) 54 { 55 unsigned long newpid = cpu_asid(vma->vm_mm); 56 57 start &= TLB_ENTRY_SIZE_MASK; 58 end += TLB_ENTRY_SIZE - 1; 59 end &= TLB_ENTRY_SIZE_MASK; 60 61 #ifdef CONFIG_CPU_HAS_TLBI 62 sync_is(); 63 while (start < end) { 64 asm volatile( 65 "tlbi.vas %0 \n" 66 : 67 : "r" (start | newpid) 68 : "memory"); 69 70 start += 2*PAGE_SIZE; 71 } 72 asm volatile("sync.i\n"); 73 #else 74 { 75 unsigned long flags, oldpid; 76 77 local_irq_save(flags); 78 oldpid = read_mmu_entryhi() & ASID_MASK; 79 while (start < end) { 80 int idx; 81 82 write_mmu_entryhi(start | newpid); 83 start += 2*PAGE_SIZE; 84 tlb_probe(); 85 idx = read_mmu_index(); 86 if (idx >= 0) 87 tlb_invalid_indexed(); 88 } 89 restore_asid_inv_utlb(oldpid, newpid); 90 local_irq_restore(flags); 91 } 92 #endif 93 } 94 95 void flush_tlb_kernel_range(unsigned long start, unsigned long end) 96 { 97 start &= TLB_ENTRY_SIZE_MASK; 98 end += TLB_ENTRY_SIZE - 1; 99 end &= TLB_ENTRY_SIZE_MASK; 100 101 #ifdef CONFIG_CPU_HAS_TLBI 102 sync_is(); 103 while (start < end) { 104 asm volatile( 105 "tlbi.vaas %0 \n" 106 : 107 : "r" (start) 108 : "memory"); 109 110 start += 2*PAGE_SIZE; 111 } 112 asm volatile("sync.i\n"); 113 #else 114 { 115 unsigned long flags, oldpid; 116 117 local_irq_save(flags); 118 oldpid = read_mmu_entryhi() & ASID_MASK; 119 while (start < end) { 120 int idx; 121 122 write_mmu_entryhi(start | oldpid); 123 start += 2*PAGE_SIZE; 124 tlb_probe(); 125 idx = read_mmu_index(); 126 if (idx >= 0) 127 tlb_invalid_indexed(); 128 } 129 restore_asid_inv_utlb(oldpid, oldpid); 130 local_irq_restore(flags); 131 } 132 #endif 133 } 134 135 void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) 136 { 137 int newpid = cpu_asid(vma->vm_mm); 138 139 addr &= TLB_ENTRY_SIZE_MASK; 140 141 #ifdef CONFIG_CPU_HAS_TLBI 142 sync_is(); 143 asm volatile( 144 "tlbi.vas %0 \n" 145 "sync.i \n" 146 : 147 : "r" (addr | newpid) 148 : "memory"); 149 #else 150 { 151 int oldpid, idx; 152 unsigned long flags; 153 154 local_irq_save(flags); 155 oldpid = read_mmu_entryhi() & ASID_MASK; 156 write_mmu_entryhi(addr | newpid); 157 tlb_probe(); 158 idx = read_mmu_index(); 159 if (idx >= 0) 160 tlb_invalid_indexed(); 161 162 restore_asid_inv_utlb(oldpid, newpid); 163 local_irq_restore(flags); 164 } 165 #endif 166 } 167 168 void flush_tlb_one(unsigned long addr) 169 { 170 addr &= TLB_ENTRY_SIZE_MASK; 171 172 #ifdef CONFIG_CPU_HAS_TLBI 173 sync_is(); 174 asm volatile( 175 "tlbi.vaas %0 \n" 176 "sync.i \n" 177 : 178 : "r" (addr) 179 : "memory"); 180 #else 181 { 182 int oldpid, idx; 183 unsigned long flags; 184 185 local_irq_save(flags); 186 oldpid = read_mmu_entryhi() & ASID_MASK; 187 write_mmu_entryhi(addr | oldpid); 188 tlb_probe(); 189 idx = read_mmu_index(); 190 if (idx >= 0) 191 tlb_invalid_indexed(); 192 193 restore_asid_inv_utlb(oldpid, oldpid); 194 local_irq_restore(flags); 195 } 196 #endif 197 } 198 EXPORT_SYMBOL(flush_tlb_one); 199