Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jbarnes...
[linux-2.6.git] / arch / sh / mm / tlbflush_32.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         int i;
127
128         /*
129          * Flush all the TLB.
130          */
131         local_irq_save(flags);
132         jump_to_uncached();
133
134         status = __raw_readl(MMUCR);
135         status = ((status & MMUCR_URB) >> MMUCR_URB_SHIFT);
136
137         if (status == 0)
138                 status = MMUCR_URB_NENTRIES;
139
140         for (i = 0; i < status; i++)
141                 __raw_writel(0x0, MMU_UTLB_ADDRESS_ARRAY | (i << 8));
142
143         for (i = 0; i < 4; i++)
144                 __raw_writel(0x0, MMU_ITLB_ADDRESS_ARRAY | (i << 8));
145
146         back_to_cached();
147         ctrl_barrier();
148         local_irq_restore(flags);
149 }