linux/arch/sh/mm/tlbflush_64.c
<<
>>
Prefs
   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 <linux/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