2  * TLB flushing operations for SH with an MMU.
 
   4  *  Copyright (C) 1999  Niibe Yutaka
 
   5  *  Copyright (C) 2003  Paul Mundt
 
   7  * This file is subject to the terms and conditions of the GNU General Public
 
   8  * License.  See the file "COPYING" in the main directory of this archive
 
  12 #include <asm/mmu_context.h>
 
  13 #include <asm/tlbflush.h>
 
  15 void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
 
  17         unsigned int cpu = smp_processor_id();
 
  19         if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) {
 
  22                 unsigned long saved_asid = MMU_NO_ASID;
 
  24                 asid = cpu_asid(cpu, vma->vm_mm);
 
  27                 local_irq_save(flags);
 
  28                 if (vma->vm_mm != current->mm) {
 
  29                         saved_asid = get_asid();
 
  32                 local_flush_tlb_one(asid, page);
 
  33                 if (saved_asid != MMU_NO_ASID)
 
  35                 local_irq_restore(flags);
 
  39 void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
 
  42         struct mm_struct *mm = vma->vm_mm;
 
  43         unsigned int cpu = smp_processor_id();
 
  45         if (cpu_context(cpu, mm) != NO_CONTEXT) {
 
  49                 local_irq_save(flags);
 
  50                 size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 
  51                 if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
 
  52                         cpu_context(cpu, mm) = NO_CONTEXT;
 
  53                         if (mm == current->mm)
 
  54                                 activate_context(mm, cpu);
 
  57                         unsigned long saved_asid = MMU_NO_ASID;
 
  59                         asid = cpu_asid(cpu, mm);
 
  61                         end += (PAGE_SIZE - 1);
 
  63                         if (mm != current->mm) {
 
  64                                 saved_asid = get_asid();
 
  68                                 local_flush_tlb_one(asid, start);
 
  71                         if (saved_asid != MMU_NO_ASID)
 
  74                 local_irq_restore(flags);
 
  78 void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
 
  80         unsigned int cpu = smp_processor_id();
 
  84         local_irq_save(flags);
 
  85         size = (end - start + (PAGE_SIZE - 1)) >> PAGE_SHIFT;
 
  86         if (size > (MMU_NTLB_ENTRIES/4)) { /* Too many TLB to flush */
 
  87                 local_flush_tlb_all();
 
  90                 unsigned long saved_asid = get_asid();
 
  92                 asid = cpu_asid(cpu, &init_mm);
 
  94                 end += (PAGE_SIZE - 1);
 
  98                         local_flush_tlb_one(asid, start);
 
 101                 set_asid(saved_asid);
 
 103         local_irq_restore(flags);
 
 106 void local_flush_tlb_mm(struct mm_struct *mm)
 
 108         unsigned int cpu = smp_processor_id();
 
 110         /* Invalidate all TLB of this process. */
 
 111         /* Instead of invalidating each TLB, we get new MMU context. */
 
 112         if (cpu_context(cpu, mm) != NO_CONTEXT) {
 
 115                 local_irq_save(flags);
 
 116                 cpu_context(cpu, mm) = NO_CONTEXT;
 
 117                 if (mm == current->mm)
 
 118                         activate_context(mm, cpu);
 
 119                 local_irq_restore(flags);
 
 123 void local_flush_tlb_all(void)
 
 125         unsigned long flags, status;
 
 130          * Write to the MMU control register's bit:
 
 131          *      TF-bit for SH-3, TI-bit for SH-4.
 
 132          *      It's same position, bit #2.
 
 134         local_irq_save(flags);
 
 135         status = ctrl_inl(MMUCR);
 
 137         ctrl_outl(status, MMUCR);
 
 139         local_irq_restore(flags);