100a9730eSGuo Ren // SPDX-License-Identifier: GPL-2.0 200a9730eSGuo Ren // Copyright (C) 2018 Hangzhou C-SKY Microsystems co.,ltd. 300a9730eSGuo Ren 400a9730eSGuo Ren #include <linux/init.h> 500a9730eSGuo Ren #include <linux/mm.h> 600a9730eSGuo Ren #include <linux/module.h> 700a9730eSGuo Ren #include <linux/sched.h> 800a9730eSGuo Ren 900a9730eSGuo Ren #include <asm/mmu_context.h> 1000a9730eSGuo Ren #include <asm/pgtable.h> 1100a9730eSGuo Ren #include <asm/setup.h> 1200a9730eSGuo Ren 13*4e562c11SGuo Ren /* 14*4e562c11SGuo Ren * One C-SKY MMU TLB entry contain two PFN/page entry, ie: 15*4e562c11SGuo Ren * 1VPN -> 2PFN 16*4e562c11SGuo Ren */ 17*4e562c11SGuo Ren #define TLB_ENTRY_SIZE (PAGE_SIZE * 2) 18*4e562c11SGuo Ren #define TLB_ENTRY_SIZE_MASK (PAGE_MASK << 1) 19*4e562c11SGuo Ren 2000a9730eSGuo Ren void flush_tlb_all(void) 2100a9730eSGuo Ren { 2200a9730eSGuo Ren tlb_invalid_all(); 2300a9730eSGuo Ren } 2400a9730eSGuo Ren 2500a9730eSGuo Ren void flush_tlb_mm(struct mm_struct *mm) 2600a9730eSGuo Ren { 27*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 28*4e562c11SGuo Ren asm volatile("tlbi.asids %0"::"r"(cpu_asid(mm))); 29*4e562c11SGuo Ren #else 3000a9730eSGuo Ren tlb_invalid_all(); 31*4e562c11SGuo Ren #endif 3200a9730eSGuo Ren } 3300a9730eSGuo Ren 34*4e562c11SGuo Ren /* 35*4e562c11SGuo Ren * MMU operation regs only could invalid tlb entry in jtlb and we 36*4e562c11SGuo Ren * need change asid field to invalid I-utlb & D-utlb. 37*4e562c11SGuo Ren */ 38*4e562c11SGuo Ren #ifndef CONFIG_CPU_HAS_TLBI 39*4e562c11SGuo Ren #define restore_asid_inv_utlb(oldpid, newpid) \ 40*4e562c11SGuo Ren do { \ 41*4e562c11SGuo Ren if (oldpid == newpid) \ 42*4e562c11SGuo Ren write_mmu_entryhi(oldpid + 1); \ 43*4e562c11SGuo Ren write_mmu_entryhi(oldpid); \ 44*4e562c11SGuo Ren } while (0) 45*4e562c11SGuo Ren #endif 46*4e562c11SGuo Ren 4700a9730eSGuo Ren void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 4800a9730eSGuo Ren unsigned long end) 4900a9730eSGuo Ren { 50*4e562c11SGuo Ren unsigned long newpid = cpu_asid(vma->vm_mm); 51*4e562c11SGuo Ren 52*4e562c11SGuo Ren start &= TLB_ENTRY_SIZE_MASK; 53*4e562c11SGuo Ren end += TLB_ENTRY_SIZE - 1; 54*4e562c11SGuo Ren end &= TLB_ENTRY_SIZE_MASK; 55*4e562c11SGuo Ren 56*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 57*4e562c11SGuo Ren while (start < end) { 58*4e562c11SGuo Ren asm volatile("tlbi.vas %0"::"r"(start | newpid)); 59*4e562c11SGuo Ren start += 2*PAGE_SIZE; 60*4e562c11SGuo Ren } 61*4e562c11SGuo Ren sync_is(); 62*4e562c11SGuo Ren #else 63*4e562c11SGuo Ren { 64*4e562c11SGuo Ren unsigned long flags, oldpid; 65*4e562c11SGuo Ren 66*4e562c11SGuo Ren local_irq_save(flags); 67*4e562c11SGuo Ren oldpid = read_mmu_entryhi() & ASID_MASK; 68*4e562c11SGuo Ren while (start < end) { 69*4e562c11SGuo Ren int idx; 70*4e562c11SGuo Ren 71*4e562c11SGuo Ren write_mmu_entryhi(start | newpid); 72*4e562c11SGuo Ren start += 2*PAGE_SIZE; 73*4e562c11SGuo Ren tlb_probe(); 74*4e562c11SGuo Ren idx = read_mmu_index(); 75*4e562c11SGuo Ren if (idx >= 0) 76*4e562c11SGuo Ren tlb_invalid_indexed(); 77*4e562c11SGuo Ren } 78*4e562c11SGuo Ren restore_asid_inv_utlb(oldpid, newpid); 79*4e562c11SGuo Ren local_irq_restore(flags); 80*4e562c11SGuo Ren } 81*4e562c11SGuo Ren #endif 8200a9730eSGuo Ren } 8300a9730eSGuo Ren 8400a9730eSGuo Ren void flush_tlb_kernel_range(unsigned long start, unsigned long end) 8500a9730eSGuo Ren { 86*4e562c11SGuo Ren start &= TLB_ENTRY_SIZE_MASK; 87*4e562c11SGuo Ren end += TLB_ENTRY_SIZE - 1; 88*4e562c11SGuo Ren end &= TLB_ENTRY_SIZE_MASK; 89*4e562c11SGuo Ren 90*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 91*4e562c11SGuo Ren while (start < end) { 92*4e562c11SGuo Ren asm volatile("tlbi.vaas %0"::"r"(start)); 93*4e562c11SGuo Ren start += 2*PAGE_SIZE; 94*4e562c11SGuo Ren } 95*4e562c11SGuo Ren sync_is(); 96*4e562c11SGuo Ren #else 97*4e562c11SGuo Ren { 98*4e562c11SGuo Ren unsigned long flags, oldpid; 99*4e562c11SGuo Ren 100*4e562c11SGuo Ren local_irq_save(flags); 101*4e562c11SGuo Ren oldpid = read_mmu_entryhi() & ASID_MASK; 102*4e562c11SGuo Ren while (start < end) { 103*4e562c11SGuo Ren int idx; 104*4e562c11SGuo Ren 105*4e562c11SGuo Ren write_mmu_entryhi(start | oldpid); 106*4e562c11SGuo Ren start += 2*PAGE_SIZE; 107*4e562c11SGuo Ren tlb_probe(); 108*4e562c11SGuo Ren idx = read_mmu_index(); 109*4e562c11SGuo Ren if (idx >= 0) 110*4e562c11SGuo Ren tlb_invalid_indexed(); 111*4e562c11SGuo Ren } 112*4e562c11SGuo Ren restore_asid_inv_utlb(oldpid, oldpid); 113*4e562c11SGuo Ren local_irq_restore(flags); 114*4e562c11SGuo Ren } 115*4e562c11SGuo Ren #endif 11600a9730eSGuo Ren } 1179d35dc30SGuo Ren 1189d35dc30SGuo Ren void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) 11900a9730eSGuo Ren { 120*4e562c11SGuo Ren int newpid = cpu_asid(vma->vm_mm); 121*4e562c11SGuo Ren 122*4e562c11SGuo Ren addr &= TLB_ENTRY_SIZE_MASK; 123*4e562c11SGuo Ren 124*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 125*4e562c11SGuo Ren asm volatile("tlbi.vas %0"::"r"(addr | newpid)); 126*4e562c11SGuo Ren sync_is(); 127*4e562c11SGuo Ren #else 128*4e562c11SGuo Ren { 129*4e562c11SGuo Ren int oldpid, idx; 130*4e562c11SGuo Ren unsigned long flags; 131*4e562c11SGuo Ren 132*4e562c11SGuo Ren local_irq_save(flags); 133*4e562c11SGuo Ren oldpid = read_mmu_entryhi() & ASID_MASK; 134*4e562c11SGuo Ren write_mmu_entryhi(addr | newpid); 135*4e562c11SGuo Ren tlb_probe(); 136*4e562c11SGuo Ren idx = read_mmu_index(); 137*4e562c11SGuo Ren if (idx >= 0) 138*4e562c11SGuo Ren tlb_invalid_indexed(); 139*4e562c11SGuo Ren 140*4e562c11SGuo Ren restore_asid_inv_utlb(oldpid, newpid); 141*4e562c11SGuo Ren local_irq_restore(flags); 142*4e562c11SGuo Ren } 143*4e562c11SGuo Ren #endif 14400a9730eSGuo Ren } 14500a9730eSGuo Ren 1469d35dc30SGuo Ren void flush_tlb_one(unsigned long addr) 14700a9730eSGuo Ren { 148*4e562c11SGuo Ren addr &= TLB_ENTRY_SIZE_MASK; 149*4e562c11SGuo Ren 150*4e562c11SGuo Ren #ifdef CONFIG_CPU_HAS_TLBI 151*4e562c11SGuo Ren asm volatile("tlbi.vaas %0"::"r"(addr)); 152*4e562c11SGuo Ren sync_is(); 153*4e562c11SGuo Ren #else 154*4e562c11SGuo Ren { 155*4e562c11SGuo Ren int oldpid, idx; 156*4e562c11SGuo Ren unsigned long flags; 157*4e562c11SGuo Ren 158*4e562c11SGuo Ren local_irq_save(flags); 159*4e562c11SGuo Ren oldpid = read_mmu_entryhi() & ASID_MASK; 160*4e562c11SGuo Ren write_mmu_entryhi(addr | oldpid); 161*4e562c11SGuo Ren tlb_probe(); 162*4e562c11SGuo Ren idx = read_mmu_index(); 163*4e562c11SGuo Ren if (idx >= 0) 164*4e562c11SGuo Ren tlb_invalid_indexed(); 165*4e562c11SGuo Ren 166*4e562c11SGuo Ren restore_asid_inv_utlb(oldpid, oldpid); 167*4e562c11SGuo Ren local_irq_restore(flags); 168*4e562c11SGuo Ren } 169*4e562c11SGuo Ren #endif 17000a9730eSGuo Ren } 17100a9730eSGuo Ren EXPORT_SYMBOL(flush_tlb_one); 172