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  *
10  * Copyright (C) 2001 - 2007 Tensilica Inc.
11  *
12  * Chris Zankel	<chris@zankel.net>
13  */
14 
15 
16 #include <linux/linkage.h>
17 #include <linux/pgtable.h>
18 #include <asm/page.h>
19 #include <asm/asmmacro.h>
20 #include <asm/cacheasm.h>
21 #include <asm/tlbflush.h>
22 
23 
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  */
30 
31 ENTRY(clear_page)
32 
33 	abi_entry_default
34 
35 	movi	a3, 0
36 	__loopi	a2, a7, PAGE_SIZE, 32
37 	s32i	a3, a2, 0
38 	s32i	a3, a2, 4
39 	s32i	a3, a2, 8
40 	s32i	a3, a2, 12
41 	s32i	a3, a2, 16
42 	s32i	a3, a2, 20
43 	s32i	a3, a2, 24
44 	s32i	a3, a2, 28
45 	__endla	a2, a7, 32
46 
47 	abi_ret_default
48 
49 ENDPROC(clear_page)
50 
51 /*
52  * copy_page and copy_user_page are the same for non-cache-aliased configs.
53  *
54  * copy_page (void *to, void *from)
55  *               a2          a3
56  */
57 
58 ENTRY(copy_page)
59 
60 	abi_entry_default
61 
62 	__loopi a2, a4, PAGE_SIZE, 32
63 
64 	l32i    a8, a3, 0
65 	l32i    a9, a3, 4
66 	s32i    a8, a2, 0
67 	s32i    a9, a2, 4
68 
69 	l32i    a8, a3, 8
70 	l32i    a9, a3, 12
71 	s32i    a8, a2, 8
72 	s32i    a9, a2, 12
73 
74 	l32i    a8, a3, 16
75 	l32i    a9, a3, 20
76 	s32i    a8, a2, 16
77 	s32i    a9, a2, 20
78 
79 	l32i    a8, a3, 24
80 	l32i    a9, a3, 28
81 	s32i    a8, a2, 24
82 	s32i    a9, a2, 28
83 
84 	addi    a2, a2, 32
85 	addi    a3, a3, 32
86 
87 	__endl  a2, a4
88 
89 	abi_ret_default
90 
91 ENDPROC(copy_page)
92 
93 #ifdef CONFIG_MMU
94 /*
95  * If we have to deal with cache aliasing, we use temporary memory mappings
96  * to ensure that the source and destination pages have the same color as
97  * the virtual address. We use way 0 and 1 for temporary mappings in such cases.
98  *
99  * The temporary DTLB entries shouldn't be flushed by interrupts, but are
100  * flushed by preemptive task switches. Special code in the
101  * fast_second_level_miss handler re-established the temporary mapping.
102  * It requires that the PPNs for the destination and source addresses are
103  * in a6, and a7, respectively.
104  */
105 
106 /* TLB miss exceptions are treated special in the following region */
107 
108 ENTRY(__tlbtemp_mapping_start)
109 
110 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
111 
112 /*
113  * clear_page_alias(void *addr, unsigned long paddr)
114  *                     a2              a3
115  */
116 
117 ENTRY(clear_page_alias)
118 
119 	abi_entry_default
120 
121 	/* Skip setting up a temporary DTLB if not aliased low page. */
122 
123 	movi	a5, PAGE_OFFSET
124 	movi	a6, 0
125 	beqz	a3, 1f
126 
127 	/* Setup a temporary DTLB for the addr. */
128 
129 	addi	a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
130 	mov	a4, a2
131 	wdtlb	a6, a2
132 	dsync
133 
134 1:	movi	a3, 0
135 	__loopi	a2, a7, PAGE_SIZE, 32
136 	s32i	a3, a2, 0
137 	s32i	a3, a2, 4
138 	s32i	a3, a2, 8
139 	s32i	a3, a2, 12
140 	s32i	a3, a2, 16
141 	s32i	a3, a2, 20
142 	s32i	a3, a2, 24
143 	s32i	a3, a2, 28
144 	__endla	a2, a7, 32
145 
146 	bnez	a6, 1f
147 	abi_ret_default
148 
149 	/* We need to invalidate the temporary idtlb entry, if any. */
150 
151 1:	idtlb	a4
152 	dsync
153 
154 	abi_ret_default
155 
156 ENDPROC(clear_page_alias)
157 
158 /*
159  * copy_page_alias(void *to, void *from,
160  *			a2	  a3
161  *                 unsigned long to_paddr, unsigned long from_paddr)
162  *	        		 a4			 a5
163  */
164 
165 ENTRY(copy_page_alias)
166 
167 	abi_entry_default
168 
169 	/* Skip setting up a temporary DTLB for destination if not aliased. */
170 
171 	movi	a6, 0
172 	movi	a7, 0
173 	beqz	a4, 1f
174 
175 	/* Setup a temporary DTLB for destination. */
176 
177 	addi	a6, a4, (PAGE_KERNEL | _PAGE_HW_WRITE)
178 	wdtlb	a6, a2
179 	dsync
180 
181 	/* Skip setting up a temporary DTLB for source if not aliased. */
182 
183 1:	beqz	a5, 1f
184 
185 	/* Setup a temporary DTLB for source. */
186 
187 	addi	a7, a5, PAGE_KERNEL
188 	addi	a8, a3, 1				# way1
189 
190 	wdtlb	a7, a8
191 	dsync
192 
193 1:	__loopi a2, a4, PAGE_SIZE, 32
194 
195 	l32i    a8, a3, 0
196 	l32i    a9, a3, 4
197 	s32i    a8, a2, 0
198 	s32i    a9, a2, 4
199 
200 	l32i    a8, a3, 8
201 	l32i    a9, a3, 12
202 	s32i    a8, a2, 8
203 	s32i    a9, a2, 12
204 
205 	l32i    a8, a3, 16
206 	l32i    a9, a3, 20
207 	s32i    a8, a2, 16
208 	s32i    a9, a2, 20
209 
210 	l32i    a8, a3, 24
211 	l32i    a9, a3, 28
212 	s32i    a8, a2, 24
213 	s32i    a9, a2, 28
214 
215 	addi    a2, a2, 32
216 	addi    a3, a3, 32
217 
218 	__endl  a2, a4
219 
220 	/* We need to invalidate any temporary mapping! */
221 
222 	bnez	a6, 1f
223 	bnez	a7, 2f
224 	abi_ret_default
225 
226 1:	addi	a2, a2, -PAGE_SIZE
227 	idtlb	a2
228 	dsync
229 	bnez	a7, 2f
230 	abi_ret_default
231 
232 2:	addi	a3, a3, -PAGE_SIZE+1
233 	idtlb	a3
234 	dsync
235 
236 	abi_ret_default
237 
238 ENDPROC(copy_page_alias)
239 
240 #endif
241 
242 #if (DCACHE_WAY_SIZE > PAGE_SIZE)
243 
244 /*
245  * void __flush_invalidate_dcache_page_alias (addr, phys)
246  *                                             a2    a3
247  */
248 
249 ENTRY(__flush_invalidate_dcache_page_alias)
250 
251 	abi_entry_default
252 
253 	movi	a7, 0			# required for exception handler
254 	addi	a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
255 	mov	a4, a2
256 	wdtlb	a6, a2
257 	dsync
258 
259 	___flush_invalidate_dcache_page a2 a3
260 
261 	idtlb	a4
262 	dsync
263 
264 	abi_ret_default
265 
266 ENDPROC(__flush_invalidate_dcache_page_alias)
267 
268 /*
269  * void __invalidate_dcache_page_alias (addr, phys)
270  *                                       a2    a3
271  */
272 
273 ENTRY(__invalidate_dcache_page_alias)
274 
275 	abi_entry_default
276 
277 	movi	a7, 0			# required for exception handler
278 	addi	a6, a3, (PAGE_KERNEL | _PAGE_HW_WRITE)
279 	mov	a4, a2
280 	wdtlb	a6, a2
281 	dsync
282 
283 	___invalidate_dcache_page a2 a3
284 
285 	idtlb	a4
286 	dsync
287 
288 	abi_ret_default
289 
290 ENDPROC(__invalidate_dcache_page_alias)
291 #endif
292 
293 ENTRY(__tlbtemp_mapping_itlb)
294 
295 #if (ICACHE_WAY_SIZE > PAGE_SIZE)
296 
297 ENTRY(__invalidate_icache_page_alias)
298 
299 	abi_entry_default
300 
301 	addi	a6, a3, (PAGE_KERNEL_EXEC | _PAGE_HW_WRITE)
302 	mov	a4, a2
303 	witlb	a6, a2
304 	isync
305 
306 	___invalidate_icache_page a2 a3
307 
308 	iitlb	a4
309 	isync
310 	abi_ret_default
311 
312 ENDPROC(__invalidate_icache_page_alias)
313 
314 #endif
315 
316 /* End of special treatment in tlb miss exception */
317 
318 ENTRY(__tlbtemp_mapping_end)
319 
320 #endif /* CONFIG_MMU
321 
322 /*
323  * void __invalidate_icache_page(ulong start)
324  */
325 
326 ENTRY(__invalidate_icache_page)
327 
328 	abi_entry_default
329 
330 	___invalidate_icache_page a2 a3
331 	isync
332 
333 	abi_ret_default
334 
335 ENDPROC(__invalidate_icache_page)
336 
337 /*
338  * void __invalidate_dcache_page(ulong start)
339  */
340 
341 ENTRY(__invalidate_dcache_page)
342 
343 	abi_entry_default
344 
345 	___invalidate_dcache_page a2 a3
346 	dsync
347 
348 	abi_ret_default
349 
350 ENDPROC(__invalidate_dcache_page)
351 
352 /*
353  * void __flush_invalidate_dcache_page(ulong start)
354  */
355 
356 ENTRY(__flush_invalidate_dcache_page)
357 
358 	abi_entry_default
359 
360 	___flush_invalidate_dcache_page a2 a3
361 
362 	dsync
363 	abi_ret_default
364 
365 ENDPROC(__flush_invalidate_dcache_page)
366 
367 /*
368  * void __flush_dcache_page(ulong start)
369  */
370 
371 ENTRY(__flush_dcache_page)
372 
373 	abi_entry_default
374 
375 	___flush_dcache_page a2 a3
376 
377 	dsync
378 	abi_ret_default
379 
380 ENDPROC(__flush_dcache_page)
381 
382 /*
383  * void __invalidate_icache_range(ulong start, ulong size)
384  */
385 
386 ENTRY(__invalidate_icache_range)
387 
388 	abi_entry_default
389 
390 	___invalidate_icache_range a2 a3 a4
391 	isync
392 
393 	abi_ret_default
394 
395 ENDPROC(__invalidate_icache_range)
396 
397 /*
398  * void __flush_invalidate_dcache_range(ulong start, ulong size)
399  */
400 
401 ENTRY(__flush_invalidate_dcache_range)
402 
403 	abi_entry_default
404 
405 	___flush_invalidate_dcache_range a2 a3 a4
406 	dsync
407 
408 	abi_ret_default
409 
410 ENDPROC(__flush_invalidate_dcache_range)
411 
412 /*
413  * void _flush_dcache_range(ulong start, ulong size)
414  */
415 
416 ENTRY(__flush_dcache_range)
417 
418 	abi_entry_default
419 
420 	___flush_dcache_range a2 a3 a4
421 	dsync
422 
423 	abi_ret_default
424 
425 ENDPROC(__flush_dcache_range)
426 
427 /*
428  * void _invalidate_dcache_range(ulong start, ulong size)
429  */
430 
431 ENTRY(__invalidate_dcache_range)
432 
433 	abi_entry_default
434 
435 	___invalidate_dcache_range a2 a3 a4
436 
437 	abi_ret_default
438 
439 ENDPROC(__invalidate_dcache_range)
440 
441 /*
442  * void _invalidate_icache_all(void)
443  */
444 
445 ENTRY(__invalidate_icache_all)
446 
447 	abi_entry_default
448 
449 	___invalidate_icache_all a2 a3
450 	isync
451 
452 	abi_ret_default
453 
454 ENDPROC(__invalidate_icache_all)
455 
456 /*
457  * void _flush_invalidate_dcache_all(void)
458  */
459 
460 ENTRY(__flush_invalidate_dcache_all)
461 
462 	abi_entry_default
463 
464 	___flush_invalidate_dcache_all a2 a3
465 	dsync
466 
467 	abi_ret_default
468 
469 ENDPROC(__flush_invalidate_dcache_all)
470 
471 /*
472  * void _invalidate_dcache_all(void)
473  */
474 
475 ENTRY(__invalidate_dcache_all)
476 
477 	abi_entry_default
478 
479 	___invalidate_dcache_all a2 a3
480 	dsync
481 
482 	abi_ret_default
483 
484 ENDPROC(__invalidate_dcache_all)
485