1/* 2 * arch/sh/mm/tlb-flush_64.c 3 * 4 * Copyright (C) 2000, 2001 Paolo Alberelli 5 * Copyright (C) 2003 Richard Curnow (/proc/tlb, bug fixes) 6 * Copyright (C) 2003 - 2012 Paul Mundt 7 * 8 * This file is subject to the terms and conditions of the GNU General Public 9 * License. See the file "COPYING" in the main directory of this archive 10 * for more details. 11 */ 12#include <linux/signal.h> 13#include <linux/rwsem.h> 14#include <linux/sched.h> 15#include <linux/kernel.h> 16#include <linux/errno.h> 17#include <linux/string.h> 18#include <linux/types.h> 19#include <linux/ptrace.h> 20#include <linux/mman.h> 21#include <linux/mm.h> 22#include <linux/smp.h> 23#include <linux/perf_event.h> 24#include <linux/interrupt.h> 25#include <asm/io.h> 26#include <asm/tlb.h> 27#include <asm/uaccess.h> 28#include <asm/pgalloc.h> 29#include <asm/mmu_context.h> 30 31void local_flush_tlb_one(unsigned long asid, unsigned long page) 32{ 33 unsigned long long match, pteh=0, lpage; 34 unsigned long tlb; 35 36 /* 37 * Sign-extend based on neff. 38 */ 39 lpage = neff_sign_extend(page); 40 match = (asid << PTEH_ASID_SHIFT) | PTEH_VALID; 41 match |= lpage; 42 43 for_each_itlb_entry(tlb) { 44 asm volatile ("getcfg %1, 0, %0" 45 : "=r" (pteh) 46 : "r" (tlb) ); 47 48 if (pteh == match) { 49 __flush_tlb_slot(tlb); 50 break; 51 } 52 } 53 54 for_each_dtlb_entry(tlb) { 55 asm volatile ("getcfg %1, 0, %0" 56 : "=r" (pteh) 57 : "r" (tlb) ); 58 59 if (pteh == match) { 60 __flush_tlb_slot(tlb); 61 break; 62 } 63 64 } 65} 66 67void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page) 68{ 69 unsigned long flags; 70 71 if (vma->vm_mm) { 72 page &= PAGE_MASK; 73 local_irq_save(flags); 74 local_flush_tlb_one(get_asid(), page); 75 local_irq_restore(flags); 76 } 77} 78 79void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start, 80 unsigned long end) 81{ 82 unsigned long flags; 83 unsigned long long match, pteh=0, pteh_epn, pteh_low; 84 unsigned long tlb; 85 unsigned int cpu = smp_processor_id(); 86 struct mm_struct *mm; 87 88 mm = vma->vm_mm; 89 if (cpu_context(cpu, mm) == NO_CONTEXT) 90 return; 91 92 local_irq_save(flags); 93 94 start &= PAGE_MASK; 95 end &= PAGE_MASK; 96 97 match = (cpu_asid(cpu, mm) << PTEH_ASID_SHIFT) | PTEH_VALID; 98 99 /* Flush ITLB */ 100 for_each_itlb_entry(tlb) { 101 asm volatile ("getcfg %1, 0, %0" 102 : "=r" (pteh) 103 : "r" (tlb) ); 104 105 pteh_epn = pteh & PAGE_MASK; 106 pteh_low = pteh & ~PAGE_MASK; 107 108 if (pteh_low == match && pteh_epn >= start && pteh_epn <= end) 109 __flush_tlb_slot(tlb); 110 } 111 112 /* Flush DTLB */ 113 for_each_dtlb_entry(tlb) { 114 asm volatile ("getcfg %1, 0, %0" 115 : "=r" (pteh) 116 : "r" (tlb) ); 117 118 pteh_epn = pteh & PAGE_MASK; 119 pteh_low = pteh & ~PAGE_MASK; 120 121 if (pteh_low == match && pteh_epn >= start && pteh_epn <= end) 122 __flush_tlb_slot(tlb); 123 } 124 125 local_irq_restore(flags); 126} 127 128void local_flush_tlb_mm(struct mm_struct *mm) 129{ 130 unsigned long flags; 131 unsigned int cpu = smp_processor_id(); 132 133 if (cpu_context(cpu, mm) == NO_CONTEXT) 134 return; 135 136 local_irq_save(flags); 137 138 cpu_context(cpu, mm) = NO_CONTEXT; 139 if (mm == current->mm) 140 activate_context(mm, cpu); 141 142 local_irq_restore(flags); 143} 144 145void local_flush_tlb_all(void) 146{ 147 /* Invalidate all, including shared pages, excluding fixed TLBs */ 148 unsigned long flags, tlb; 149 150 local_irq_save(flags); 151 152 /* Flush each ITLB entry */ 153 for_each_itlb_entry(tlb) 154 __flush_tlb_slot(tlb); 155 156 /* Flush each DTLB entry */ 157 for_each_dtlb_entry(tlb) 158 __flush_tlb_slot(tlb); 159 160 local_irq_restore(flags); 161} 162 163void local_flush_tlb_kernel_range(unsigned long start, unsigned long end) 164{ 165 /* FIXME: Optimize this later.. */ 166 flush_tlb_all(); 167} 168 169void __flush_tlb_global(void) 170{ 171 flush_tlb_all(); 172} 173