linux/arch/sh/mm/tlbflush_32.c
<<
>>
Prefs
   1/*
   2 * TLB flushing operations for SH with an MMU.
   3 *
   4 *  Copyright (C) 1999  Niibe Yutaka
   5 *  Copyright (C) 2003  Paul Mundt
   6 *
   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
   9 * for more details.
  10 */
  11#include <linux/mm.h>
  12#include <asm/mmu_context.h>
  13#include <asm/tlbflush.h>
  14
  15void local_flush_tlb_page(struct vm_area_struct *vma, unsigned long page)
  16{
  17        unsigned int cpu = smp_processor_id();
  18
  19        if (vma->vm_mm && cpu_context(cpu, vma->vm_mm) != NO_CONTEXT) {
  20                unsigned long flags;
  21                unsigned long asid;
  22                unsigned long saved_asid = MMU_NO_ASID;
  23
  24                asid = cpu_asid(cpu, vma->vm_mm);
  25                page &= PAGE_MASK;
  26
  27                local_irq_save(flags);
  28                if (vma->vm_mm != current->mm) {
  29                        saved_asid = get_asid();
  30                        set_asid(asid);
  31                }
  32                local_flush_tlb_one(asid, page);
  33                if (saved_asid != MMU_NO_ASID)
  34                        set_asid(saved_asid);
  35                local_irq_restore(flags);
  36        }
  37}
  38
  39void local_flush_tlb_range(struct vm_area_struct *vma, unsigned long start,
  40                           unsigned long end)
  41{
  42        struct mm_struct *mm = vma->vm_mm;
  43        unsigned int cpu = smp_processor_id();
  44
  45        if (cpu_context(cpu, mm) != NO_CONTEXT) {
  46                unsigned long flags;
  47                int size;
  48
  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);
  55                } else {
  56                        unsigned long asid;
  57                        unsigned long saved_asid = MMU_NO_ASID;
  58
  59                        asid = cpu_asid(cpu, mm);
  60                        start &= PAGE_MASK;
  61                        end += (PAGE_SIZE - 1);
  62                        end &= PAGE_MASK;
  63                        if (mm != current->mm) {
  64                                saved_asid = get_asid();
  65                                set_asid(asid);
  66                        }
  67                        while (start < end) {
  68                                local_flush_tlb_one(asid, start);
  69                                start += PAGE_SIZE;
  70                        }
  71                        if (saved_asid != MMU_NO_ASID)
  72                                set_asid(saved_asid);
  73                }
  74                local_irq_restore(flags);
  75        }
  76}
  77
  78void local_flush_tlb_kernel_range(unsigned long start, unsigned long end)
  79{
  80        unsigned int cpu = smp_processor_id();
  81        unsigned long flags;
  82        int size;
  83
  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();
  88        } else {
  89                unsigned long asid;
  90                unsigned long saved_asid = get_asid();
  91
  92                asid = cpu_asid(cpu, &init_mm);
  93                start &= PAGE_MASK;
  94                end += (PAGE_SIZE - 1);
  95                end &= PAGE_MASK;
  96                set_asid(asid);
  97                while (start < end) {
  98                        local_flush_tlb_one(asid, start);
  99                        start += PAGE_SIZE;
 100                }
 101                set_asid(saved_asid);
 102        }
 103        local_irq_restore(flags);
 104}
 105
 106void local_flush_tlb_mm(struct mm_struct *mm)
 107{
 108        unsigned int cpu = smp_processor_id();
 109
 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) {
 113                unsigned long flags;
 114
 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);
 120        }
 121}
 122
 123void __flush_tlb_global(void)
 124{
 125        unsigned long flags;
 126
 127        local_irq_save(flags);
 128
 129        /*
 130         * This is the most destructive of the TLB flushing options,
 131         * and will tear down all of the UTLB/ITLB mappings, including
 132         * wired entries.
 133         */
 134        __raw_writel(__raw_readl(MMUCR) | MMUCR_TI, MMUCR);
 135
 136        local_irq_restore(flags);
 137}
 138