xref: /openbmc/linux/arch/xtensa/mm/misc.S (revision f15cbe6f1a4b4d9df59142fc8e4abb973302cf44)
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 <asm/page.h>
18#include <asm/pgtable.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
31ENTRY(clear_page)
32	entry	a1, 16
33
34	movi	a3, 0
35	__loopi	a2, a7, PAGE_SIZE, 32
36	s32i	a3, a2, 0
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
44	__endla	a2, a7, 32
45
46	retw
47
48/*
49 * copy_page and copy_user_page are the same for non-cache-aliased configs.
50 *
51 * copy_page (void *to, void *from)
52 *               a2          a3
53 */
54
55ENTRY(copy_page)
56	entry	a1, 16
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
101ENTRY(__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
110ENTRY(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
1431:	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
1601:	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
171ENTRY(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
2071:	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
2191:	__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
2521:	addi	a2, a2, -PAGE_SIZE
253	idtlb	a2
254	dsync
255	bnez	a7, 2f
256	retw
257
2582:	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
273ENTRY(__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
291ENTRY(__tlbtemp_mapping_itlb)
292
293#if (ICACHE_WAY_SIZE > PAGE_SIZE)
294
295ENTRY(__invalidate_icache_page_alias)
296	entry	sp, 16
297
298	addi	a6, a3, (PAGE_KERNEL_EXEC | _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
307	retw
308
309#endif
310
311/* End of special treatment in tlb miss exception */
312
313ENTRY(__tlbtemp_mapping_end)
314
315/*
316 * void __invalidate_icache_page(ulong start)
317 */
318
319ENTRY(__invalidate_icache_page)
320	entry	sp, 16
321
322	___invalidate_icache_page a2 a3
323	isync
324
325	retw
326
327/*
328 * void __invalidate_dcache_page(ulong start)
329 */
330
331ENTRY(__invalidate_dcache_page)
332	entry	sp, 16
333
334	___invalidate_dcache_page a2 a3
335	dsync
336
337	retw
338
339/*
340 * void __flush_invalidate_dcache_page(ulong start)
341 */
342
343ENTRY(__flush_invalidate_dcache_page)
344	entry	sp, 16
345
346	___flush_invalidate_dcache_page a2 a3
347
348	dsync
349	retw
350
351/*
352 * void __flush_dcache_page(ulong start)
353 */
354
355ENTRY(__flush_dcache_page)
356	entry	sp, 16
357
358	___flush_dcache_page a2 a3
359
360	dsync
361	retw
362
363/*
364 * void __invalidate_icache_range(ulong start, ulong size)
365 */
366
367ENTRY(__invalidate_icache_range)
368	entry	sp, 16
369
370	___invalidate_icache_range a2 a3 a4
371	isync
372
373	retw
374
375/*
376 * void __flush_invalidate_dcache_range(ulong start, ulong size)
377 */
378
379ENTRY(__flush_invalidate_dcache_range)
380	entry	sp, 16
381
382	___flush_invalidate_dcache_range a2 a3 a4
383	dsync
384
385	retw
386
387/*
388 * void _flush_dcache_range(ulong start, ulong size)
389 */
390
391ENTRY(__flush_dcache_range)
392	entry	sp, 16
393
394	___flush_dcache_range a2 a3 a4
395	dsync
396
397	retw
398
399/*
400 * void _invalidate_dcache_range(ulong start, ulong size)
401 */
402
403ENTRY(__invalidate_dcache_range)
404	entry	sp, 16
405
406	___invalidate_dcache_range a2 a3 a4
407
408	retw
409
410/*
411 * void _invalidate_icache_all(void)
412 */
413
414ENTRY(__invalidate_icache_all)
415	entry	sp, 16
416
417	___invalidate_icache_all a2 a3
418	isync
419
420	retw
421
422/*
423 * void _flush_invalidate_dcache_all(void)
424 */
425
426ENTRY(__flush_invalidate_dcache_all)
427	entry	sp, 16
428
429	___flush_invalidate_dcache_all a2 a3
430	dsync
431
432	retw
433
434/*
435 * void _invalidate_dcache_all(void)
436 */
437
438ENTRY(__invalidate_dcache_all)
439	entry	sp, 16
440
441	___invalidate_dcache_all a2 a3
442	dsync
443
444	retw
445
446