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