tlb.c (3635B)
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 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) \ 45do { \ 46 if (oldpid == newpid) \ 47 write_mmu_entryhi(oldpid + 1); \ 48 write_mmu_entryhi(oldpid); \ 49} while (0) 50#endif 51 52void 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 95void 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 135void 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 168void 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} 198EXPORT_SYMBOL(flush_tlb_one);