Merge branch 'linus' of master.kernel.org:/pub/scm/linux/kernel/git/perex/alsa
[linux-2.6] / arch / sh / mm / tlb-flush.c
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
15 void 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
39 void 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
78 void 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
106 void 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
123 void local_flush_tlb_all(void)
124 {
125         unsigned long flags, status;
126
127         /*
128          * Flush all the TLB.
129          *
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.
133          */
134         local_irq_save(flags);
135         status = ctrl_inl(MMUCR);
136         status |= 0x04;
137         ctrl_outl(status, MMUCR);
138         ctrl_barrier();
139         local_irq_restore(flags);
140 }