diff options
Diffstat (limited to 'include/asm-m68k/tlbflush.h')
-rw-r--r-- | include/asm-m68k/tlbflush.h | 230 |
1 files changed, 230 insertions, 0 deletions
diff --git a/include/asm-m68k/tlbflush.h b/include/asm-m68k/tlbflush.h new file mode 100644 index 000000000000..8e61ccffe13a --- /dev/null +++ b/include/asm-m68k/tlbflush.h | |||
@@ -0,0 +1,230 @@ | |||
1 | #ifndef _M68K_TLBFLUSH_H | ||
2 | #define _M68K_TLBFLUSH_H | ||
3 | |||
4 | #include <linux/config.h> | ||
5 | |||
6 | #ifndef CONFIG_SUN3 | ||
7 | |||
8 | #include <asm/current.h> | ||
9 | |||
10 | static inline void flush_tlb_kernel_page(void *addr) | ||
11 | { | ||
12 | if (CPU_IS_040_OR_060) { | ||
13 | mm_segment_t old_fs = get_fs(); | ||
14 | set_fs(KERNEL_DS); | ||
15 | __asm__ __volatile__(".chip 68040\n\t" | ||
16 | "pflush (%0)\n\t" | ||
17 | ".chip 68k" | ||
18 | : : "a" (addr)); | ||
19 | set_fs(old_fs); | ||
20 | } else | ||
21 | __asm__ __volatile__("pflush #4,#4,(%0)" : : "a" (addr)); | ||
22 | } | ||
23 | |||
24 | /* | ||
25 | * flush all user-space atc entries. | ||
26 | */ | ||
27 | static inline void __flush_tlb(void) | ||
28 | { | ||
29 | if (CPU_IS_040_OR_060) | ||
30 | __asm__ __volatile__(".chip 68040\n\t" | ||
31 | "pflushan\n\t" | ||
32 | ".chip 68k"); | ||
33 | else | ||
34 | __asm__ __volatile__("pflush #0,#4"); | ||
35 | } | ||
36 | |||
37 | static inline void __flush_tlb040_one(unsigned long addr) | ||
38 | { | ||
39 | __asm__ __volatile__(".chip 68040\n\t" | ||
40 | "pflush (%0)\n\t" | ||
41 | ".chip 68k" | ||
42 | : : "a" (addr)); | ||
43 | } | ||
44 | |||
45 | static inline void __flush_tlb_one(unsigned long addr) | ||
46 | { | ||
47 | if (CPU_IS_040_OR_060) | ||
48 | __flush_tlb040_one(addr); | ||
49 | else | ||
50 | __asm__ __volatile__("pflush #0,#4,(%0)" : : "a" (addr)); | ||
51 | } | ||
52 | |||
53 | #define flush_tlb() __flush_tlb() | ||
54 | |||
55 | /* | ||
56 | * flush all atc entries (both kernel and user-space entries). | ||
57 | */ | ||
58 | static inline void flush_tlb_all(void) | ||
59 | { | ||
60 | if (CPU_IS_040_OR_060) | ||
61 | __asm__ __volatile__(".chip 68040\n\t" | ||
62 | "pflusha\n\t" | ||
63 | ".chip 68k"); | ||
64 | else | ||
65 | __asm__ __volatile__("pflusha"); | ||
66 | } | ||
67 | |||
68 | static inline void flush_tlb_mm(struct mm_struct *mm) | ||
69 | { | ||
70 | if (mm == current->active_mm) | ||
71 | __flush_tlb(); | ||
72 | } | ||
73 | |||
74 | static inline void flush_tlb_page(struct vm_area_struct *vma, unsigned long addr) | ||
75 | { | ||
76 | if (vma->vm_mm == current->active_mm) { | ||
77 | mm_segment_t old_fs = get_fs(); | ||
78 | set_fs(USER_DS); | ||
79 | __flush_tlb_one(addr); | ||
80 | set_fs(old_fs); | ||
81 | } | ||
82 | } | ||
83 | |||
84 | static inline void flush_tlb_range(struct vm_area_struct *vma, | ||
85 | unsigned long start, unsigned long end) | ||
86 | { | ||
87 | if (vma->vm_mm == current->active_mm) | ||
88 | __flush_tlb(); | ||
89 | } | ||
90 | |||
91 | static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
92 | { | ||
93 | flush_tlb_all(); | ||
94 | } | ||
95 | |||
96 | static inline void flush_tlb_pgtables(struct mm_struct *mm, | ||
97 | unsigned long start, unsigned long end) | ||
98 | { | ||
99 | } | ||
100 | |||
101 | #else | ||
102 | |||
103 | |||
104 | /* Reserved PMEGs. */ | ||
105 | extern char sun3_reserved_pmeg[SUN3_PMEGS_NUM]; | ||
106 | extern unsigned long pmeg_vaddr[SUN3_PMEGS_NUM]; | ||
107 | extern unsigned char pmeg_alloc[SUN3_PMEGS_NUM]; | ||
108 | extern unsigned char pmeg_ctx[SUN3_PMEGS_NUM]; | ||
109 | |||
110 | /* Flush all userspace mappings one by one... (why no flush command, | ||
111 | sun?) */ | ||
112 | static inline void flush_tlb_all(void) | ||
113 | { | ||
114 | unsigned long addr; | ||
115 | unsigned char ctx, oldctx; | ||
116 | |||
117 | oldctx = sun3_get_context(); | ||
118 | for(addr = 0x00000000; addr < TASK_SIZE; addr += SUN3_PMEG_SIZE) { | ||
119 | for(ctx = 0; ctx < 8; ctx++) { | ||
120 | sun3_put_context(ctx); | ||
121 | sun3_put_segmap(addr, SUN3_INVALID_PMEG); | ||
122 | } | ||
123 | } | ||
124 | |||
125 | sun3_put_context(oldctx); | ||
126 | /* erase all of the userspace pmeg maps, we've clobbered them | ||
127 | all anyway */ | ||
128 | for(addr = 0; addr < SUN3_INVALID_PMEG; addr++) { | ||
129 | if(pmeg_alloc[addr] == 1) { | ||
130 | pmeg_alloc[addr] = 0; | ||
131 | pmeg_ctx[addr] = 0; | ||
132 | pmeg_vaddr[addr] = 0; | ||
133 | } | ||
134 | } | ||
135 | |||
136 | } | ||
137 | |||
138 | /* Clear user TLB entries within the context named in mm */ | ||
139 | static inline void flush_tlb_mm (struct mm_struct *mm) | ||
140 | { | ||
141 | unsigned char oldctx; | ||
142 | unsigned char seg; | ||
143 | unsigned long i; | ||
144 | |||
145 | oldctx = sun3_get_context(); | ||
146 | sun3_put_context(mm->context); | ||
147 | |||
148 | for(i = 0; i < TASK_SIZE; i += SUN3_PMEG_SIZE) { | ||
149 | seg = sun3_get_segmap(i); | ||
150 | if(seg == SUN3_INVALID_PMEG) | ||
151 | continue; | ||
152 | |||
153 | sun3_put_segmap(i, SUN3_INVALID_PMEG); | ||
154 | pmeg_alloc[seg] = 0; | ||
155 | pmeg_ctx[seg] = 0; | ||
156 | pmeg_vaddr[seg] = 0; | ||
157 | } | ||
158 | |||
159 | sun3_put_context(oldctx); | ||
160 | |||
161 | } | ||
162 | |||
163 | /* Flush a single TLB page. In this case, we're limited to flushing a | ||
164 | single PMEG */ | ||
165 | static inline void flush_tlb_page (struct vm_area_struct *vma, | ||
166 | unsigned long addr) | ||
167 | { | ||
168 | unsigned char oldctx; | ||
169 | unsigned char i; | ||
170 | |||
171 | oldctx = sun3_get_context(); | ||
172 | sun3_put_context(vma->vm_mm->context); | ||
173 | addr &= ~SUN3_PMEG_MASK; | ||
174 | if((i = sun3_get_segmap(addr)) != SUN3_INVALID_PMEG) | ||
175 | { | ||
176 | pmeg_alloc[i] = 0; | ||
177 | pmeg_ctx[i] = 0; | ||
178 | pmeg_vaddr[i] = 0; | ||
179 | sun3_put_segmap (addr, SUN3_INVALID_PMEG); | ||
180 | } | ||
181 | sun3_put_context(oldctx); | ||
182 | |||
183 | } | ||
184 | /* Flush a range of pages from TLB. */ | ||
185 | |||
186 | static inline void flush_tlb_range (struct vm_area_struct *vma, | ||
187 | unsigned long start, unsigned long end) | ||
188 | { | ||
189 | struct mm_struct *mm = vma->vm_mm; | ||
190 | unsigned char seg, oldctx; | ||
191 | |||
192 | start &= ~SUN3_PMEG_MASK; | ||
193 | |||
194 | oldctx = sun3_get_context(); | ||
195 | sun3_put_context(mm->context); | ||
196 | |||
197 | while(start < end) | ||
198 | { | ||
199 | if((seg = sun3_get_segmap(start)) == SUN3_INVALID_PMEG) | ||
200 | goto next; | ||
201 | if(pmeg_ctx[seg] == mm->context) { | ||
202 | pmeg_alloc[seg] = 0; | ||
203 | pmeg_ctx[seg] = 0; | ||
204 | pmeg_vaddr[seg] = 0; | ||
205 | } | ||
206 | sun3_put_segmap(start, SUN3_INVALID_PMEG); | ||
207 | next: | ||
208 | start += SUN3_PMEG_SIZE; | ||
209 | } | ||
210 | } | ||
211 | |||
212 | static inline void flush_tlb_kernel_range(unsigned long start, unsigned long end) | ||
213 | { | ||
214 | flush_tlb_all(); | ||
215 | } | ||
216 | |||
217 | /* Flush kernel page from TLB. */ | ||
218 | static inline void flush_tlb_kernel_page (unsigned long addr) | ||
219 | { | ||
220 | sun3_put_segmap (addr & ~(SUN3_PMEG_SIZE - 1), SUN3_INVALID_PMEG); | ||
221 | } | ||
222 | |||
223 | static inline void flush_tlb_pgtables(struct mm_struct *mm, | ||
224 | unsigned long start, unsigned long end) | ||
225 | { | ||
226 | } | ||
227 | |||
228 | #endif | ||
229 | |||
230 | #endif /* _M68K_TLBFLUSH_H */ | ||