diff options
Diffstat (limited to 'arch/xtensa/mm/misc.S')
-rw-r--r-- | arch/xtensa/mm/misc.S | 306 |
1 files changed, 271 insertions, 35 deletions
diff --git a/arch/xtensa/mm/misc.S b/arch/xtensa/mm/misc.S index ae085332c607..e1f880368e32 100644 --- a/arch/xtensa/mm/misc.S +++ b/arch/xtensa/mm/misc.S | |||
@@ -7,29 +7,33 @@ | |||
7 | * License. See the file "COPYING" in the main directory of this archive | 7 | * License. See the file "COPYING" in the main directory of this archive |
8 | * for more details. | 8 | * for more details. |
9 | * | 9 | * |
10 | * Copyright (C) 2001 - 2005 Tensilica Inc. | 10 | * Copyright (C) 2001 - 2007 Tensilica Inc. |
11 | * | 11 | * |
12 | * Chris Zankel <chris@zankel.net> | 12 | * Chris Zankel <chris@zankel.net> |
13 | */ | 13 | */ |
14 | 14 | ||
15 | /* Note: we might want to implement some of the loops as zero-overhead-loops, | ||
16 | * where applicable and if supported by the processor. | ||
17 | */ | ||
18 | 15 | ||
19 | #include <linux/linkage.h> | 16 | #include <linux/linkage.h> |
20 | #include <asm/page.h> | 17 | #include <asm/page.h> |
21 | #include <asm/pgtable.h> | 18 | #include <asm/pgtable.h> |
22 | #include <asm/asmmacro.h> | 19 | #include <asm/asmmacro.h> |
23 | #include <asm/cacheasm.h> | 20 | #include <asm/cacheasm.h> |
21 | #include <asm/tlbflush.h> | ||
22 | |||
24 | 23 | ||
25 | /* clear_page (page) */ | 24 | /* |
25 | * clear_page and clear_user_page are the same for non-cache-aliased configs. | ||
26 | * | ||
27 | * clear_page (unsigned long page) | ||
28 | * a2 | ||
29 | */ | ||
26 | 30 | ||
27 | ENTRY(clear_page) | 31 | ENTRY(clear_page) |
28 | entry a1, 16 | 32 | entry a1, 16 |
29 | addi a4, a2, PAGE_SIZE | ||
30 | movi a3, 0 | ||
31 | 33 | ||
32 | 1: s32i a3, a2, 0 | 34 | movi a3, 0 |
35 | __loopi a2, a7, PAGE_SIZE, 32 | ||
36 | s32i a3, a2, 0 | ||
33 | s32i a3, a2, 4 | 37 | s32i a3, a2, 4 |
34 | s32i a3, a2, 8 | 38 | s32i a3, a2, 8 |
35 | s32i a3, a2, 12 | 39 | s32i a3, a2, 12 |
@@ -37,42 +41,277 @@ ENTRY(clear_page) | |||
37 | s32i a3, a2, 20 | 41 | s32i a3, a2, 20 |
38 | s32i a3, a2, 24 | 42 | s32i a3, a2, 24 |
39 | s32i a3, a2, 28 | 43 | s32i a3, a2, 28 |
40 | addi a2, a2, 32 | 44 | __endla a2, a7, 32 |
41 | blt a2, a4, 1b | ||
42 | 45 | ||
43 | retw | 46 | retw |
44 | 47 | ||
45 | /* | 48 | /* |
49 | * copy_page and copy_user_page are the same for non-cache-aliased configs. | ||
50 | * | ||
46 | * copy_page (void *to, void *from) | 51 | * copy_page (void *to, void *from) |
47 | * a2 a3 | 52 | * a2 a3 |
48 | */ | 53 | */ |
49 | 54 | ||
50 | ENTRY(copy_page) | 55 | ENTRY(copy_page) |
51 | entry a1, 16 | 56 | entry a1, 16 |
52 | addi a4, a2, PAGE_SIZE | ||
53 | |||
54 | 1: l32i a5, a3, 0 | ||
55 | l32i a6, a3, 4 | ||
56 | l32i a7, a3, 8 | ||
57 | s32i a5, a2, 0 | ||
58 | s32i a6, a2, 4 | ||
59 | s32i a7, a2, 8 | ||
60 | l32i a5, a3, 12 | ||
61 | l32i a6, a3, 16 | ||
62 | l32i a7, a3, 20 | ||
63 | s32i a5, a2, 12 | ||
64 | s32i a6, a2, 16 | ||
65 | s32i a7, a2, 20 | ||
66 | l32i a5, a3, 24 | ||
67 | l32i a6, a3, 28 | ||
68 | s32i a5, a2, 24 | ||
69 | s32i a6, a2, 28 | ||
70 | addi a2, a2, 32 | ||
71 | addi a3, a3, 32 | ||
72 | blt a2, a4, 1b | ||
73 | 57 | ||
58 | __loopi a2, a4, PAGE_SIZE, 32 | ||
59 | |||
60 | l32i a8, a3, 0 | ||
61 | l32i a9, a3, 4 | ||
62 | s32i a8, a2, 0 | ||
63 | s32i a9, a2, 4 | ||
64 | |||
65 | l32i a8, a3, 8 | ||
66 | l32i a9, a3, 12 | ||
67 | s32i a8, a2, 8 | ||
68 | s32i a9, a2, 12 | ||
69 | |||
70 | l32i a8, a3, 16 | ||
71 | l32i a9, a3, 20 | ||
72 | s32i a8, a2, 16 | ||
73 | s32i a9, a2, 20 | ||
74 | |||
75 | l32i a8, a3, 24 | ||
76 | l32i a9, a3, 28 | ||
77 | s32i a8, a2, 24 | ||
78 | s32i a9, a2, 28 | ||
79 | |||
80 | addi a2, a2, 32 | ||
81 | addi a3, a3, 32 | ||
82 | |||
83 | __endl a2, a4 | ||
84 | |||
85 | retw | ||
86 | |||
87 | /* | ||
88 | * If we have to deal with cache aliasing, we use temporary memory mappings | ||
89 | * to ensure that the source and destination pages have the same color as | ||
90 | * the virtual address. We use way 0 and 1 for temporary mappings in such cases. | ||
91 | * | ||
92 | * The temporary DTLB entries shouldn't be flushed by interrupts, but are | ||
93 | * flushed by preemptive task switches. Special code in the | ||
94 | * fast_second_level_miss handler re-established the temporary mapping. | ||
95 | * It requires that the PPNs for the destination and source addresses are | ||
96 | * in a6, and a7, respectively. | ||
97 | */ | ||
98 | |||
99 | /* TLB miss exceptions are treated special in the following region */ | ||
100 | |||
101 | ENTRY(__tlbtemp_mapping_start) | ||
102 | |||
103 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) | ||
104 | |||
105 | /* | ||
106 | * clear_user_page (void *addr, unsigned long vaddr, struct page *page) | ||
107 | * a2 a3 a4 | ||
108 | */ | ||
109 | |||
110 | ENTRY(clear_user_page) | ||
111 | entry a1, 32 | ||
112 | |||
113 | /* Mark page dirty and determine alias. */ | ||
114 | |||
115 | movi a7, (1 << PG_ARCH_1) | ||
116 | l32i a5, a4, PAGE_FLAGS | ||
117 | xor a6, a2, a3 | ||
118 | extui a3, a3, PAGE_SHIFT, DCACHE_ALIAS_ORDER | ||
119 | extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER | ||
120 | or a5, a5, a7 | ||
121 | slli a3, a3, PAGE_SHIFT | ||
122 | s32i a5, a4, PAGE_FLAGS | ||
123 | |||
124 | /* Skip setting up a temporary DTLB if not aliased. */ | ||
125 | |||
126 | beqz a6, 1f | ||
127 | |||
128 | /* Invalidate kernel page. */ | ||
129 | |||
130 | mov a10, a2 | ||
131 | call8 __invalidate_dcache_page | ||
132 | |||
133 | /* Setup a temporary DTLB with the color of the VPN */ | ||
134 | |||
135 | movi a4, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE) | ||
136 | movi a5, TLBTEMP_BASE_1 # virt | ||
137 | add a6, a2, a4 # ppn | ||
138 | add a2, a5, a3 # add 'color' | ||
139 | |||
140 | wdtlb a6, a2 | ||
141 | dsync | ||
142 | |||
143 | 1: movi a3, 0 | ||
144 | __loopi a2, a7, PAGE_SIZE, 32 | ||
145 | s32i a3, a2, 0 | ||
146 | s32i a3, a2, 4 | ||
147 | s32i a3, a2, 8 | ||
148 | s32i a3, a2, 12 | ||
149 | s32i a3, a2, 16 | ||
150 | s32i a3, a2, 20 | ||
151 | s32i a3, a2, 24 | ||
152 | s32i a3, a2, 28 | ||
153 | __endla a2, a7, 32 | ||
154 | |||
155 | bnez a6, 1f | ||
156 | retw | ||
157 | |||
158 | /* We need to invalidate the temporary idtlb entry, if any. */ | ||
159 | |||
160 | 1: addi a2, a2, -PAGE_SIZE | ||
161 | idtlb a2 | ||
162 | dsync | ||
163 | |||
164 | retw | ||
165 | |||
166 | /* | ||
167 | * copy_page_user (void *to, void *from, unsigned long vaddr, struct page *page) | ||
168 | * a2 a3 a4 a5 | ||
169 | */ | ||
170 | |||
171 | ENTRY(copy_user_page) | ||
172 | |||
173 | entry a1, 32 | ||
174 | |||
175 | /* Mark page dirty and determine alias for destination. */ | ||
176 | |||
177 | movi a8, (1 << PG_ARCH_1) | ||
178 | l32i a9, a5, PAGE_FLAGS | ||
179 | xor a6, a2, a4 | ||
180 | xor a7, a3, a4 | ||
181 | extui a4, a4, PAGE_SHIFT, DCACHE_ALIAS_ORDER | ||
182 | extui a6, a6, PAGE_SHIFT, DCACHE_ALIAS_ORDER | ||
183 | extui a7, a7, PAGE_SHIFT, DCACHE_ALIAS_ORDER | ||
184 | or a9, a9, a8 | ||
185 | slli a4, a4, PAGE_SHIFT | ||
186 | s32i a9, a5, PAGE_FLAGS | ||
187 | movi a5, -PAGE_OFFSET + (PAGE_KERNEL | _PAGE_HW_WRITE) | ||
188 | |||
189 | beqz a6, 1f | ||
190 | |||
191 | /* Invalidate dcache */ | ||
192 | |||
193 | mov a10, a2 | ||
194 | call8 __invalidate_dcache_page | ||
195 | |||
196 | /* Setup a temporary DTLB with a matching color. */ | ||
197 | |||
198 | movi a8, TLBTEMP_BASE_1 # base | ||
199 | add a6, a2, a5 # ppn | ||
200 | add a2, a8, a4 # add 'color' | ||
201 | |||
202 | wdtlb a6, a2 | ||
203 | dsync | ||
204 | |||
205 | /* Skip setting up a temporary DTLB for destination if not aliased. */ | ||
206 | |||
207 | 1: beqz a7, 1f | ||
208 | |||
209 | /* Setup a temporary DTLB with a matching color. */ | ||
210 | |||
211 | movi a8, TLBTEMP_BASE_2 # base | ||
212 | add a7, a3, a5 # ppn | ||
213 | add a3, a8, a4 | ||
214 | addi a8, a3, 1 # way1 | ||
215 | |||
216 | wdtlb a7, a8 | ||
217 | dsync | ||
218 | |||
219 | 1: __loopi a2, a4, PAGE_SIZE, 32 | ||
220 | |||
221 | l32i a8, a3, 0 | ||
222 | l32i a9, a3, 4 | ||
223 | s32i a8, a2, 0 | ||
224 | s32i a9, a2, 4 | ||
225 | |||
226 | l32i a8, a3, 8 | ||
227 | l32i a9, a3, 12 | ||
228 | s32i a8, a2, 8 | ||
229 | s32i a9, a2, 12 | ||
230 | |||
231 | l32i a8, a3, 16 | ||
232 | l32i a9, a3, 20 | ||
233 | s32i a8, a2, 16 | ||
234 | s32i a9, a2, 20 | ||
235 | |||
236 | l32i a8, a3, 24 | ||
237 | l32i a9, a3, 28 | ||
238 | s32i a8, a2, 24 | ||
239 | s32i a9, a2, 28 | ||
240 | |||
241 | addi a2, a2, 32 | ||
242 | addi a3, a3, 32 | ||
243 | |||
244 | __endl a2, a4 | ||
245 | |||
246 | /* We need to invalidate any temporary mapping! */ | ||
247 | |||
248 | bnez a6, 1f | ||
249 | bnez a7, 2f | ||
250 | retw | ||
251 | |||
252 | 1: addi a2, a2, -PAGE_SIZE | ||
253 | idtlb a2 | ||
254 | dsync | ||
255 | bnez a7, 2f | ||
256 | retw | ||
257 | |||
258 | 2: addi a3, a3, -PAGE_SIZE+1 | ||
259 | idtlb a3 | ||
260 | dsync | ||
261 | |||
262 | retw | ||
263 | |||
264 | #endif | ||
265 | |||
266 | #if (DCACHE_WAY_SIZE > PAGE_SIZE) | ||
267 | |||
268 | /* | ||
269 | * void __flush_invalidate_dcache_page_alias (addr, phys) | ||
270 | * a2 a3 | ||
271 | */ | ||
272 | |||
273 | ENTRY(__flush_invalidate_dcache_page_alias) | ||
274 | entry sp, 16 | ||
275 | |||
276 | movi a7, 0 # required for exception handler | ||
277 | addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE) | ||
278 | mov a4, a2 | ||
279 | wdtlb a6, a2 | ||
280 | dsync | ||
281 | |||
282 | ___flush_invalidate_dcache_page a2 a3 | ||
283 | |||
284 | idtlb a4 | ||
285 | dsync | ||
286 | |||
287 | retw | ||
288 | |||
289 | #endif | ||
290 | |||
291 | ENTRY(__tlbtemp_mapping_itlb) | ||
292 | |||
293 | #if (ICACHE_WAY_SIZE > PAGE_SIZE) | ||
294 | |||
295 | ENTRY(__invalidate_icache_page_alias) | ||
296 | entry sp, 16 | ||
297 | |||
298 | addi a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE) | ||
299 | mov a4, a2 | ||
300 | witlb a6, a2 | ||
301 | isync | ||
302 | |||
303 | ___invalidate_icache_page a2 a3 | ||
304 | |||
305 | iitlb a4 | ||
306 | isync | ||
74 | retw | 307 | retw |
75 | 308 | ||
309 | #endif | ||
310 | |||
311 | /* End of special treatment in tlb miss exception */ | ||
312 | |||
313 | ENTRY(__tlbtemp_mapping_end) | ||
314 | |||
76 | /* | 315 | /* |
77 | * void __invalidate_icache_page(ulong start) | 316 | * void __invalidate_icache_page(ulong start) |
78 | */ | 317 | */ |
@@ -121,8 +360,6 @@ ENTRY(__flush_dcache_page) | |||
121 | dsync | 360 | dsync |
122 | retw | 361 | retw |
123 | 362 | ||
124 | |||
125 | |||
126 | /* | 363 | /* |
127 | * void __invalidate_icache_range(ulong start, ulong size) | 364 | * void __invalidate_icache_range(ulong start, ulong size) |
128 | */ | 365 | */ |
@@ -168,7 +405,6 @@ ENTRY(__invalidate_dcache_range) | |||
168 | 405 | ||
169 | ___invalidate_dcache_range a2 a3 a4 | 406 | ___invalidate_dcache_range a2 a3 a4 |
170 | 407 | ||
171 | |||
172 | retw | 408 | retw |
173 | 409 | ||
174 | /* | 410 | /* |