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 19void flush_tlb_all(void) 20{ 21 tlb_invalid_all(); 22} 23 24void flush_tlb_mm(struct mm_struct *mm) 25{ 26#ifdef CONFIG_CPU_HAS_TLBI 27 asm volatile("tlbi.asids %0"::"r"(cpu_asid(mm))); 28#else 29 tlb_invalid_all(); 30#endif 31} 32 33/* 34 * MMU operation regs only could invalid tlb entry in jtlb and we 35 * need change asid field to invalid I-utlb & D-utlb. 36 */ 37#ifndef CONFIG_CPU_HAS_TLBI 38#define restore_asid_inv_utlb(oldpid, newpid) \ 39do { \ 40 if (oldpid == newpid) \ 41 write_mmu_entryhi(oldpid + 1); \ 42 write_mmu_entryhi(oldpid); \ 43} while (0) 44#endif 45 46void flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 47 unsigned long end) 48{ 49 unsigned long newpid = cpu_asid(vma->vm_mm); 50 51 start &= TLB_ENTRY_SIZE_MASK; 52 end += TLB_ENTRY_SIZE - 1; 53 end &= TLB_ENTRY_SIZE_MASK; 54 55#ifdef CONFIG_CPU_HAS_TLBI 56 while (start < end) { 57 asm volatile("tlbi.vas %0"::"r"(start | newpid)); 58 start += 2*PAGE_SIZE; 59 } 60 sync_is(); 61#else 62 { 63 unsigned long flags, oldpid; 64 65 local_irq_save(flags); 66 oldpid = read_mmu_entryhi() & ASID_MASK; 67 while (start < end) { 68 int idx; 69 70 write_mmu_entryhi(start | newpid); 71 start += 2*PAGE_SIZE; 72 tlb_probe(); 73 idx = read_mmu_index(); 74 if (idx >= 0) 75 tlb_invalid_indexed(); 76 } 77 restore_asid_inv_utlb(oldpid, newpid); 78 local_irq_restore(flags); 79 } 80#endif 81} 82 83void flush_tlb_kernel_range(unsigned long start, unsigned long end) 84{ 85 start &= TLB_ENTRY_SIZE_MASK; 86 end += TLB_ENTRY_SIZE - 1; 87 end &= TLB_ENTRY_SIZE_MASK; 88 89#ifdef CONFIG_CPU_HAS_TLBI 90 while (start < end) { 91 asm volatile("tlbi.vaas %0"::"r"(start)); 92 start += 2*PAGE_SIZE; 93 } 94 sync_is(); 95#else 96 { 97 unsigned long flags, oldpid; 98 99 local_irq_save(flags); 100 oldpid = read_mmu_entryhi() & ASID_MASK; 101 while (start < end) { 102 int idx; 103 104 write_mmu_entryhi(start | oldpid); 105 start += 2*PAGE_SIZE; 106 tlb_probe(); 107 idx = read_mmu_index(); 108 if (idx >= 0) 109 tlb_invalid_indexed(); 110 } 111 restore_asid_inv_utlb(oldpid, oldpid); 112 local_irq_restore(flags); 113 } 114#endif 115} 116 117void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) 118{ 119 int newpid = cpu_asid(vma->vm_mm); 120 121 addr &= TLB_ENTRY_SIZE_MASK; 122 123#ifdef CONFIG_CPU_HAS_TLBI 124 asm volatile("tlbi.vas %0"::"r"(addr | newpid)); 125 sync_is(); 126#else 127 { 128 int oldpid, idx; 129 unsigned long flags; 130 131 local_irq_save(flags); 132 oldpid = read_mmu_entryhi() & ASID_MASK; 133 write_mmu_entryhi(addr | newpid); 134 tlb_probe(); 135 idx = read_mmu_index(); 136 if (idx >= 0) 137 tlb_invalid_indexed(); 138 139 restore_asid_inv_utlb(oldpid, newpid); 140 local_irq_restore(flags); 141 } 142#endif 143} 144 145void flush_tlb_one(unsigned long addr) 146{ 147 addr &= TLB_ENTRY_SIZE_MASK; 148 149#ifdef CONFIG_CPU_HAS_TLBI 150 asm volatile("tlbi.vaas %0"::"r"(addr)); 151 sync_is(); 152#else 153 { 154 int oldpid, idx; 155 unsigned long flags; 156 157 local_irq_save(flags); 158 oldpid = read_mmu_entryhi() & ASID_MASK; 159 write_mmu_entryhi(addr | oldpid); 160 tlb_probe(); 161 idx = read_mmu_index(); 162 if (idx >= 0) 163 tlb_invalid_indexed(); 164 165 restore_asid_inv_utlb(oldpid, oldpid); 166 local_irq_restore(flags); 167 } 168#endif 169} 170EXPORT_SYMBOL(flush_tlb_one); 171