Commit | Line | Data |
---|---|---|
3f65ce4d CZ |
1 | /* |
2 | * arch/xtensa/mm/misc.S | |
3 | * | |
4 | * Miscellaneous assembly functions. | |
5 | * | |
6 | * This file is subject to the terms and conditions of the GNU General Public | |
7 | * License. See the file "COPYING" in the main directory of this archive | |
8 | * for more details. | |
9 | * | |
6656920b | 10 | * Copyright (C) 2001 - 2007 Tensilica Inc. |
3f65ce4d CZ |
11 | * |
12 | * Chris Zankel <chris@zankel.net> | |
13 | */ | |
14 | ||
3f65ce4d CZ |
15 | |
16 | #include <linux/linkage.h> | |
17 | #include <asm/page.h> | |
18 | #include <asm/pgtable.h> | |
173d6681 CZ |
19 | #include <asm/asmmacro.h> |
20 | #include <asm/cacheasm.h> | |
6656920b CZ |
21 | #include <asm/tlbflush.h> |
22 | ||
3f65ce4d | 23 | |
6656920b CZ |
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 | */ | |
3f65ce4d CZ |
30 | |
31 | ENTRY(clear_page) | |
32 | entry a1, 16 | |
3f65ce4d | 33 | |
6656920b CZ |
34 | movi a3, 0 |
35 | __loopi a2, a7, PAGE_SIZE, 32 | |
36 | s32i a3, a2, 0 | |
3f65ce4d CZ |
37 | s32i a3, a2, 4 |
38 | s32i a3, a2, 8 | |
39 | s32i a3, a2, 12 | |
40 | s32i a3, a2, 16 | |
41 | s32i a3, a2, 20 | |
42 | s32i a3, a2, 24 | |
43 | s32i a3, a2, 28 | |
6656920b | 44 | __endla a2, a7, 32 |
3f65ce4d CZ |
45 | |
46 | retw | |
47 | ||
48 | /* | |
6656920b CZ |
49 | * copy_page and copy_user_page are the same for non-cache-aliased configs. |
50 | * | |
3f65ce4d | 51 | * copy_page (void *to, void *from) |
6656920b | 52 | * a2 a3 |
3f65ce4d CZ |
53 | */ |
54 | ||
55 | ENTRY(copy_page) | |
56 | entry a1, 16 | |
3f65ce4d | 57 | |
6656920b CZ |
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 | ||
0b2c3afd | 298 | addi a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE) |
6656920b CZ |
299 | mov a4, a2 |
300 | witlb a6, a2 | |
301 | isync | |
302 | ||
303 | ___invalidate_icache_page a2 a3 | |
304 | ||
305 | iitlb a4 | |
306 | isync | |
3f65ce4d CZ |
307 | retw |
308 | ||
6656920b CZ |
309 | #endif |
310 | ||
311 | /* End of special treatment in tlb miss exception */ | |
312 | ||
313 | ENTRY(__tlbtemp_mapping_end) | |
314 | ||
3f65ce4d | 315 | /* |
173d6681 | 316 | * void __invalidate_icache_page(ulong start) |
3f65ce4d CZ |
317 | */ |
318 | ||
173d6681 | 319 | ENTRY(__invalidate_icache_page) |
3f65ce4d | 320 | entry sp, 16 |
3f65ce4d | 321 | |
173d6681 CZ |
322 | ___invalidate_icache_page a2 a3 |
323 | isync | |
3f65ce4d | 324 | |
3f65ce4d CZ |
325 | retw |
326 | ||
327 | /* | |
173d6681 | 328 | * void __invalidate_dcache_page(ulong start) |
3f65ce4d CZ |
329 | */ |
330 | ||
173d6681 | 331 | ENTRY(__invalidate_dcache_page) |
3f65ce4d | 332 | entry sp, 16 |
3f65ce4d | 333 | |
173d6681 CZ |
334 | ___invalidate_dcache_page a2 a3 |
335 | dsync | |
3f65ce4d | 336 | |
3f65ce4d CZ |
337 | retw |
338 | ||
339 | /* | |
173d6681 | 340 | * void __flush_invalidate_dcache_page(ulong start) |
3f65ce4d CZ |
341 | */ |
342 | ||
173d6681 | 343 | ENTRY(__flush_invalidate_dcache_page) |
3f65ce4d | 344 | entry sp, 16 |
3f65ce4d | 345 | |
173d6681 | 346 | ___flush_invalidate_dcache_page a2 a3 |
3f65ce4d | 347 | |
173d6681 | 348 | dsync |
3f65ce4d CZ |
349 | retw |
350 | ||
351 | /* | |
173d6681 | 352 | * void __flush_dcache_page(ulong start) |
3f65ce4d CZ |
353 | */ |
354 | ||
173d6681 | 355 | ENTRY(__flush_dcache_page) |
3f65ce4d | 356 | entry sp, 16 |
3f65ce4d | 357 | |
173d6681 | 358 | ___flush_dcache_page a2 a3 |
3f65ce4d | 359 | |
173d6681 | 360 | dsync |
3f65ce4d CZ |
361 | retw |
362 | ||
3f65ce4d | 363 | /* |
173d6681 | 364 | * void __invalidate_icache_range(ulong start, ulong size) |
3f65ce4d CZ |
365 | */ |
366 | ||
173d6681 | 367 | ENTRY(__invalidate_icache_range) |
3f65ce4d | 368 | entry sp, 16 |
173d6681 CZ |
369 | |
370 | ___invalidate_icache_range a2 a3 a4 | |
371 | isync | |
372 | ||
3f65ce4d CZ |
373 | retw |
374 | ||
375 | /* | |
376 | * void __flush_invalidate_dcache_range(ulong start, ulong size) | |
377 | */ | |
378 | ||
379 | ENTRY(__flush_invalidate_dcache_range) | |
380 | entry sp, 16 | |
3f65ce4d | 381 | |
173d6681 CZ |
382 | ___flush_invalidate_dcache_range a2 a3 a4 |
383 | dsync | |
3f65ce4d | 384 | |
3f65ce4d CZ |
385 | retw |
386 | ||
387 | /* | |
173d6681 | 388 | * void _flush_dcache_range(ulong start, ulong size) |
3f65ce4d CZ |
389 | */ |
390 | ||
173d6681 | 391 | ENTRY(__flush_dcache_range) |
3f65ce4d CZ |
392 | entry sp, 16 |
393 | ||
173d6681 | 394 | ___flush_dcache_range a2 a3 a4 |
3f65ce4d | 395 | dsync |
3f65ce4d | 396 | |
3f65ce4d CZ |
397 | retw |
398 | ||
173d6681 CZ |
399 | /* |
400 | * void _invalidate_dcache_range(ulong start, ulong size) | |
401 | */ | |
3f65ce4d | 402 | |
173d6681 | 403 | ENTRY(__invalidate_dcache_range) |
3f65ce4d CZ |
404 | entry sp, 16 |
405 | ||
173d6681 | 406 | ___invalidate_dcache_range a2 a3 a4 |
3f65ce4d | 407 | |
3f65ce4d CZ |
408 | retw |
409 | ||
173d6681 CZ |
410 | /* |
411 | * void _invalidate_icache_all(void) | |
412 | */ | |
3f65ce4d | 413 | |
173d6681 | 414 | ENTRY(__invalidate_icache_all) |
3f65ce4d CZ |
415 | entry sp, 16 |
416 | ||
173d6681 CZ |
417 | ___invalidate_icache_all a2 a3 |
418 | isync | |
3f65ce4d | 419 | |
3f65ce4d CZ |
420 | retw |
421 | ||
3f65ce4d | 422 | /* |
173d6681 | 423 | * void _flush_invalidate_dcache_all(void) |
3f65ce4d CZ |
424 | */ |
425 | ||
173d6681 | 426 | ENTRY(__flush_invalidate_dcache_all) |
3f65ce4d CZ |
427 | entry sp, 16 |
428 | ||
173d6681 CZ |
429 | ___flush_invalidate_dcache_all a2 a3 |
430 | dsync | |
3f65ce4d | 431 | |
3f65ce4d CZ |
432 | retw |
433 | ||
173d6681 CZ |
434 | /* |
435 | * void _invalidate_dcache_all(void) | |
436 | */ | |
3f65ce4d | 437 | |
173d6681 | 438 | ENTRY(__invalidate_dcache_all) |
3f65ce4d CZ |
439 | entry sp, 16 |
440 | ||
173d6681 CZ |
441 | ___invalidate_dcache_all a2 a3 |
442 | dsync | |
3f65ce4d CZ |
443 | |
444 | retw | |
445 |