1*00a9730eSGuo Ren // SPDX-License-Identifier: GPL-2.0 2*00a9730eSGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 3*00a9730eSGuo Ren 4*00a9730eSGuo Ren #include <linux/init.h> 5*00a9730eSGuo Ren #include <linux/mm.h> 6*00a9730eSGuo Ren #include <linux/module.h> 7*00a9730eSGuo Ren #include <linux/sched.h> 8*00a9730eSGuo Ren 9*00a9730eSGuo Ren #include <asm/mmu_context.h> 10*00a9730eSGuo Ren #include <asm/pgtable.h> 11*00a9730eSGuo Ren #include <asm/setup.h> 12*00a9730eSGuo Ren 13*00a9730eSGuo Ren #define CSKY_TLB_SIZE CONFIG_CPU_TLB_SIZE 14*00a9730eSGuo Ren 15*00a9730eSGuo Ren void flush_tlb_all(void) 16*00a9730eSGuo Ren { 17*00a9730eSGuo Ren tlb_invalid_all(); 18*00a9730eSGuo Ren } 19*00a9730eSGuo Ren 20*00a9730eSGuo Ren void flush_tlb_mm(struct mm_struct *mm) 21*00a9730eSGuo Ren { 22*00a9730eSGuo Ren int cpu = smp_processor_id(); 23*00a9730eSGuo Ren 24*00a9730eSGuo Ren if (cpu_context(cpu, mm) != 0) 25*00a9730eSGuo Ren drop_mmu_context(mm, cpu); 26*00a9730eSGuo Ren 27*00a9730eSGuo Ren tlb_invalid_all(); 28*00a9730eSGuo Ren } 29*00a9730eSGuo Ren 30*00a9730eSGuo Ren #define restore_asid_inv_utlb(oldpid, newpid) \ 31*00a9730eSGuo Ren do { \ 32*00a9730eSGuo Ren if ((oldpid & ASID_MASK) == newpid) \ 33*00a9730eSGuo Ren write_mmu_entryhi(oldpid + 1); \ 34*00a9730eSGuo Ren write_mmu_entryhi(oldpid); \ 35*00a9730eSGuo Ren } while (0) 36*00a9730eSGuo Ren 37*00a9730eSGuo Ren void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 38*00a9730eSGuo Ren unsigned long end) 39*00a9730eSGuo Ren { 40*00a9730eSGuo Ren struct mm_struct *mm = vma->vm_mm; 41*00a9730eSGuo Ren int cpu = smp_processor_id(); 42*00a9730eSGuo Ren 43*00a9730eSGuo Ren if (cpu_context(cpu, mm) != 0) { 44*00a9730eSGuo Ren unsigned long size, flags; 45*00a9730eSGuo Ren int newpid = cpu_asid(cpu, mm); 46*00a9730eSGuo Ren 47*00a9730eSGuo Ren local_irq_save(flags); 48*00a9730eSGuo Ren size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 49*00a9730eSGuo Ren size = (size + 1) >> 1; 50*00a9730eSGuo Ren if (size <= CSKY_TLB_SIZE/2) { 51*00a9730eSGuo Ren start &= (PAGE_MASK << 1); 52*00a9730eSGuo Ren end += ((PAGE_SIZE << 1) - 1); 53*00a9730eSGuo Ren end &= (PAGE_MASK << 1); 54*00a9730eSGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 55*00a9730eSGuo Ren while (start < end) { 56*00a9730eSGuo Ren asm volatile("tlbi.vaas %0" 57*00a9730eSGuo Ren ::"r"(start | newpid)); 58*00a9730eSGuo Ren start += (PAGE_SIZE << 1); 59*00a9730eSGuo Ren } 60*00a9730eSGuo Ren sync_is(); 61*00a9730eSGuo Ren #else 62*00a9730eSGuo Ren { 63*00a9730eSGuo Ren int oldpid = read_mmu_entryhi(); 64*00a9730eSGuo Ren 65*00a9730eSGuo Ren while (start < end) { 66*00a9730eSGuo Ren int idx; 67*00a9730eSGuo Ren 68*00a9730eSGuo Ren write_mmu_entryhi(start | newpid); 69*00a9730eSGuo Ren start += (PAGE_SIZE << 1); 70*00a9730eSGuo Ren tlb_probe(); 71*00a9730eSGuo Ren idx = read_mmu_index(); 72*00a9730eSGuo Ren if (idx >= 0) 73*00a9730eSGuo Ren tlb_invalid_indexed(); 74*00a9730eSGuo Ren } 75*00a9730eSGuo Ren restore_asid_inv_utlb(oldpid, newpid); 76*00a9730eSGuo Ren } 77*00a9730eSGuo Ren #endif 78*00a9730eSGuo Ren } else { 79*00a9730eSGuo Ren drop_mmu_context(mm, cpu); 80*00a9730eSGuo Ren } 81*00a9730eSGuo Ren local_irq_restore(flags); 82*00a9730eSGuo Ren } 83*00a9730eSGuo Ren } 84*00a9730eSGuo Ren 85*00a9730eSGuo Ren void flush_tlb_kernel_range(unsigned long start, unsigned long end) 86*00a9730eSGuo Ren { 87*00a9730eSGuo Ren unsigned long size, flags; 88*00a9730eSGuo Ren 89*00a9730eSGuo Ren local_irq_save(flags); 90*00a9730eSGuo Ren size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT; 91*00a9730eSGuo Ren if (size <= CSKY_TLB_SIZE) { 92*00a9730eSGuo Ren start &= (PAGE_MASK << 1); 93*00a9730eSGuo Ren end += ((PAGE_SIZE << 1) - 1); 94*00a9730eSGuo Ren end &= (PAGE_MASK << 1); 95*00a9730eSGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 96*00a9730eSGuo Ren while (start < end) { 97*00a9730eSGuo Ren asm volatile("tlbi.vaas %0"::"r"(start)); 98*00a9730eSGuo Ren start += (PAGE_SIZE << 1); 99*00a9730eSGuo Ren } 100*00a9730eSGuo Ren sync_is(); 101*00a9730eSGuo Ren #else 102*00a9730eSGuo Ren { 103*00a9730eSGuo Ren int oldpid = read_mmu_entryhi(); 104*00a9730eSGuo Ren 105*00a9730eSGuo Ren while (start < end) { 106*00a9730eSGuo Ren int idx; 107*00a9730eSGuo Ren 108*00a9730eSGuo Ren write_mmu_entryhi(start); 109*00a9730eSGuo Ren start += (PAGE_SIZE << 1); 110*00a9730eSGuo Ren tlb_probe(); 111*00a9730eSGuo Ren idx = read_mmu_index(); 112*00a9730eSGuo Ren if (idx >= 0) 113*00a9730eSGuo Ren tlb_invalid_indexed(); 114*00a9730eSGuo Ren } 115*00a9730eSGuo Ren restore_asid_inv_utlb(oldpid, 0); 116*00a9730eSGuo Ren } 117*00a9730eSGuo Ren #endif 118*00a9730eSGuo Ren } else { 119*00a9730eSGuo Ren flush_tlb_all(); 120*00a9730eSGuo Ren } 121*00a9730eSGuo Ren 122*00a9730eSGuo Ren local_irq_restore(flags); 123*00a9730eSGuo Ren } 124*00a9730eSGuo Ren 125*00a9730eSGuo Ren void flush_tlb_page(struct vm_area_struct *vma, unsigned long page) 126*00a9730eSGuo Ren { 127*00a9730eSGuo Ren int cpu = smp_processor_id(); 128*00a9730eSGuo Ren int newpid = cpu_asid(cpu, vma->vm_mm); 129*00a9730eSGuo Ren 130*00a9730eSGuo Ren if (!vma || cpu_context(cpu, vma->vm_mm) != 0) { 131*00a9730eSGuo Ren page &= (PAGE_MASK << 1); 132*00a9730eSGuo Ren 133*00a9730eSGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 134*00a9730eSGuo Ren asm volatile("tlbi.vaas %0"::"r"(page | newpid)); 135*00a9730eSGuo Ren sync_is(); 136*00a9730eSGuo Ren #else 137*00a9730eSGuo Ren { 138*00a9730eSGuo Ren int oldpid, idx; 139*00a9730eSGuo Ren unsigned long flags; 140*00a9730eSGuo Ren 141*00a9730eSGuo Ren local_irq_save(flags); 142*00a9730eSGuo Ren oldpid = read_mmu_entryhi(); 143*00a9730eSGuo Ren write_mmu_entryhi(page | newpid); 144*00a9730eSGuo Ren tlb_probe(); 145*00a9730eSGuo Ren idx = read_mmu_index(); 146*00a9730eSGuo Ren if (idx >= 0) 147*00a9730eSGuo Ren tlb_invalid_indexed(); 148*00a9730eSGuo Ren 149*00a9730eSGuo Ren restore_asid_inv_utlb(oldpid, newpid); 150*00a9730eSGuo Ren local_irq_restore(flags); 151*00a9730eSGuo Ren } 152*00a9730eSGuo Ren #endif 153*00a9730eSGuo Ren } 154*00a9730eSGuo Ren } 155*00a9730eSGuo Ren 156*00a9730eSGuo Ren /* 157*00a9730eSGuo Ren * Remove one kernel space TLB entry. This entry is assumed to be marked 158*00a9730eSGuo Ren * global so we don't do the ASID thing. 159*00a9730eSGuo Ren */ 160*00a9730eSGuo Ren void flush_tlb_one(unsigned long page) 161*00a9730eSGuo Ren { 162*00a9730eSGuo Ren int oldpid; 163*00a9730eSGuo Ren 164*00a9730eSGuo Ren oldpid = read_mmu_entryhi(); 165*00a9730eSGuo Ren page &= (PAGE_MASK << 1); 166*00a9730eSGuo Ren 167*00a9730eSGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 168*00a9730eSGuo Ren page = page | (oldpid & 0xfff); 169*00a9730eSGuo Ren asm volatile("tlbi.vaas %0"::"r"(page)); 170*00a9730eSGuo Ren sync_is(); 171*00a9730eSGuo Ren #else 172*00a9730eSGuo Ren { 173*00a9730eSGuo Ren int idx; 174*00a9730eSGuo Ren unsigned long flags; 175*00a9730eSGuo Ren 176*00a9730eSGuo Ren page = page | (oldpid & 0xff); 177*00a9730eSGuo Ren 178*00a9730eSGuo Ren local_irq_save(flags); 179*00a9730eSGuo Ren write_mmu_entryhi(page); 180*00a9730eSGuo Ren tlb_probe(); 181*00a9730eSGuo Ren idx = read_mmu_index(); 182*00a9730eSGuo Ren if (idx >= 0) 183*00a9730eSGuo Ren tlb_invalid_indexed(); 184*00a9730eSGuo Ren restore_asid_inv_utlb(oldpid, oldpid); 185*00a9730eSGuo Ren local_irq_restore(flags); 186*00a9730eSGuo Ren } 187*00a9730eSGuo Ren #endif 188*00a9730eSGuo Ren } 189*00a9730eSGuo Ren EXPORT_SYMBOL(flush_tlb_one); 190*00a9730eSGuo Ren 191*00a9730eSGuo Ren /* show current 32 jtlbs */ 192*00a9730eSGuo Ren void show_jtlb_table(void) 193*00a9730eSGuo Ren { 194*00a9730eSGuo Ren unsigned long flags; 195*00a9730eSGuo Ren int entryhi, entrylo0, entrylo1; 196*00a9730eSGuo Ren int entry; 197*00a9730eSGuo Ren int oldpid; 198*00a9730eSGuo Ren 199*00a9730eSGuo Ren local_irq_save(flags); 200*00a9730eSGuo Ren entry = 0; 201*00a9730eSGuo Ren pr_info("\n\n\n"); 202*00a9730eSGuo Ren 203*00a9730eSGuo Ren oldpid = read_mmu_entryhi(); 204*00a9730eSGuo Ren while (entry < CSKY_TLB_SIZE) { 205*00a9730eSGuo Ren write_mmu_index(entry); 206*00a9730eSGuo Ren tlb_read(); 207*00a9730eSGuo Ren entryhi = read_mmu_entryhi(); 208*00a9730eSGuo Ren entrylo0 = read_mmu_entrylo0(); 209*00a9730eSGuo Ren entrylo0 = entrylo0; 210*00a9730eSGuo Ren entrylo1 = read_mmu_entrylo1(); 211*00a9730eSGuo Ren entrylo1 = entrylo1; 212*00a9730eSGuo Ren pr_info("jtlb[%d]: entryhi - 0x%x; entrylo0 - 0x%x;" 213*00a9730eSGuo Ren " entrylo1 - 0x%x\n", 214*00a9730eSGuo Ren entry, entryhi, entrylo0, entrylo1); 215*00a9730eSGuo Ren entry++; 216*00a9730eSGuo Ren } 217*00a9730eSGuo Ren write_mmu_entryhi(oldpid); 218*00a9730eSGuo Ren local_irq_restore(flags); 219*00a9730eSGuo Ren } 220