Merge rsync://rsync.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6-block.git] / arch / sparc64 / mm / ultra.S
CommitLineData
1da177e4
LT
1/* $Id: ultra.S,v 1.72 2002/02/09 19:49:31 davem Exp $
2 * ultra.S: Don't expand these all over the place...
3 *
4 * Copyright (C) 1997, 2000 David S. Miller (davem@redhat.com)
5 */
6
7#include <linux/config.h>
8#include <asm/asi.h>
9#include <asm/pgtable.h>
10#include <asm/page.h>
11#include <asm/spitfire.h>
12#include <asm/mmu_context.h>
13#include <asm/pil.h>
14#include <asm/head.h>
15#include <asm/thread_info.h>
16#include <asm/cacheflush.h>
17
18 /* Basically, most of the Spitfire vs. Cheetah madness
19 * has to do with the fact that Cheetah does not support
20 * IMMU flushes out of the secondary context. Someone needs
21 * to throw a south lake birthday party for the folks
22 * in Microelectronics who refused to fix this shit.
23 */
24
25 /* This file is meant to be read efficiently by the CPU, not humans.
26 * Staraj sie tego nikomu nie pierdolnac...
27 */
28 .text
29 .align 32
30 .globl __flush_tlb_mm
31__flush_tlb_mm: /* %o0=(ctx & TAG_CONTEXT_BITS), %o1=SECONDARY_CONTEXT */
32 ldxa [%o1] ASI_DMMU, %g2
33 cmp %g2, %o0
34 bne,pn %icc, __spitfire_flush_tlb_mm_slow
35 mov 0x50, %g3
36 stxa %g0, [%g3] ASI_DMMU_DEMAP
37 stxa %g0, [%g3] ASI_IMMU_DEMAP
38 retl
39 flush %g6
40 nop
41 nop
42 nop
43 nop
44 nop
45 nop
46 nop
47 nop
48
49 .align 32
50 .globl __flush_tlb_pending
51__flush_tlb_pending:
52 /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
53 rdpr %pstate, %g7
54 sllx %o1, 3, %o1
55 andn %g7, PSTATE_IE, %g2
56 wrpr %g2, %pstate
57 mov SECONDARY_CONTEXT, %o4
58 ldxa [%o4] ASI_DMMU, %g2
59 stxa %o0, [%o4] ASI_DMMU
601: sub %o1, (1 << 3), %o1
61 ldx [%o2 + %o1], %o3
62 andcc %o3, 1, %g0
63 andn %o3, 1, %o3
64 be,pn %icc, 2f
65 or %o3, 0x10, %o3
66 stxa %g0, [%o3] ASI_IMMU_DEMAP
672: stxa %g0, [%o3] ASI_DMMU_DEMAP
68 membar #Sync
69 brnz,pt %o1, 1b
70 nop
71 stxa %g2, [%o4] ASI_DMMU
72 flush %g6
73 retl
74 wrpr %g7, 0x0, %pstate
75
76 .align 32
77 .globl __flush_tlb_kernel_range
78__flush_tlb_kernel_range: /* %o0=start, %o1=end */
79 cmp %o0, %o1
80 be,pn %xcc, 2f
81 sethi %hi(PAGE_SIZE), %o4
82 sub %o1, %o0, %o3
83 sub %o3, %o4, %o3
84 or %o0, 0x20, %o0 ! Nucleus
851: stxa %g0, [%o0 + %o3] ASI_DMMU_DEMAP
86 stxa %g0, [%o0 + %o3] ASI_IMMU_DEMAP
87 membar #Sync
88 brnz,pt %o3, 1b
89 sub %o3, %o4, %o3
902: retl
91 flush %g6
92
93__spitfire_flush_tlb_mm_slow:
94 rdpr %pstate, %g1
95 wrpr %g1, PSTATE_IE, %pstate
96 stxa %o0, [%o1] ASI_DMMU
97 stxa %g0, [%g3] ASI_DMMU_DEMAP
98 stxa %g0, [%g3] ASI_IMMU_DEMAP
99 flush %g6
100 stxa %g2, [%o1] ASI_DMMU
101 flush %g6
102 retl
103 wrpr %g1, 0, %pstate
104
105/*
106 * The following code flushes one page_size worth.
107 */
108#if (PAGE_SHIFT == 13)
109#define ITAG_MASK 0xfe
110#elif (PAGE_SHIFT == 16)
111#define ITAG_MASK 0x7fe
112#else
113#error unsupported PAGE_SIZE
114#endif
115 .align 32
116 .globl __flush_icache_page
117__flush_icache_page: /* %o0 = phys_page */
118 membar #StoreStore
119 srlx %o0, PAGE_SHIFT, %o0
120 sethi %uhi(PAGE_OFFSET), %g1
121 sllx %o0, PAGE_SHIFT, %o0
122 sethi %hi(PAGE_SIZE), %g2
123 sllx %g1, 32, %g1
124 add %o0, %g1, %o0
1251: subcc %g2, 32, %g2
126 bne,pt %icc, 1b
127 flush %o0 + %g2
128 retl
129 nop
130
131#ifdef DCACHE_ALIASING_POSSIBLE
132
133#if (PAGE_SHIFT != 13)
134#error only page shift of 13 is supported by dcache flush
135#endif
136
137#define DTAG_MASK 0x3
138
139 .align 64
140 .globl __flush_dcache_page
141__flush_dcache_page: /* %o0=kaddr, %o1=flush_icache */
142 sethi %uhi(PAGE_OFFSET), %g1
143 sllx %g1, 32, %g1
144 sub %o0, %g1, %o0
145 clr %o4
146 srlx %o0, 11, %o0
147 sethi %hi(1 << 14), %o2
1481: ldxa [%o4] ASI_DCACHE_TAG, %o3 ! LSU Group
149 add %o4, (1 << 5), %o4 ! IEU0
150 ldxa [%o4] ASI_DCACHE_TAG, %g1 ! LSU Group
151 add %o4, (1 << 5), %o4 ! IEU0
152 ldxa [%o4] ASI_DCACHE_TAG, %g2 ! LSU Group o3 available
153 add %o4, (1 << 5), %o4 ! IEU0
154 andn %o3, DTAG_MASK, %o3 ! IEU1
155 ldxa [%o4] ASI_DCACHE_TAG, %g3 ! LSU Group
156 add %o4, (1 << 5), %o4 ! IEU0
157 andn %g1, DTAG_MASK, %g1 ! IEU1
158 cmp %o0, %o3 ! IEU1 Group
159 be,a,pn %xcc, dflush1 ! CTI
160 sub %o4, (4 << 5), %o4 ! IEU0 (Group)
161 cmp %o0, %g1 ! IEU1 Group
162 andn %g2, DTAG_MASK, %g2 ! IEU0
163 be,a,pn %xcc, dflush2 ! CTI
164 sub %o4, (3 << 5), %o4 ! IEU0 (Group)
165 cmp %o0, %g2 ! IEU1 Group
166 andn %g3, DTAG_MASK, %g3 ! IEU0
167 be,a,pn %xcc, dflush3 ! CTI
168 sub %o4, (2 << 5), %o4 ! IEU0 (Group)
169 cmp %o0, %g3 ! IEU1 Group
170 be,a,pn %xcc, dflush4 ! CTI
171 sub %o4, (1 << 5), %o4 ! IEU0
1722: cmp %o4, %o2 ! IEU1 Group
173 bne,pt %xcc, 1b ! CTI
174 nop ! IEU0
175
176 /* The I-cache does not snoop local stores so we
177 * better flush that too when necessary.
178 */
179 brnz,pt %o1, __flush_icache_page
180 sllx %o0, 11, %o0
181 retl
182 nop
183
184dflush1:stxa %g0, [%o4] ASI_DCACHE_TAG
185 add %o4, (1 << 5), %o4
186dflush2:stxa %g0, [%o4] ASI_DCACHE_TAG
187 add %o4, (1 << 5), %o4
188dflush3:stxa %g0, [%o4] ASI_DCACHE_TAG
189 add %o4, (1 << 5), %o4
190dflush4:stxa %g0, [%o4] ASI_DCACHE_TAG
191 add %o4, (1 << 5), %o4
192 membar #Sync
193 ba,pt %xcc, 2b
194 nop
195#endif /* DCACHE_ALIASING_POSSIBLE */
196
197 .align 32
198__prefill_dtlb:
199 rdpr %pstate, %g7
200 wrpr %g7, PSTATE_IE, %pstate
201 mov TLB_TAG_ACCESS, %g1
202 stxa %o5, [%g1] ASI_DMMU
203 stxa %o2, [%g0] ASI_DTLB_DATA_IN
204 flush %g6
205 retl
206 wrpr %g7, %pstate
207__prefill_itlb:
208 rdpr %pstate, %g7
209 wrpr %g7, PSTATE_IE, %pstate
210 mov TLB_TAG_ACCESS, %g1
211 stxa %o5, [%g1] ASI_IMMU
212 stxa %o2, [%g0] ASI_ITLB_DATA_IN
213 flush %g6
214 retl
215 wrpr %g7, %pstate
216
217 .globl __update_mmu_cache
218__update_mmu_cache: /* %o0=hw_context, %o1=address, %o2=pte, %o3=fault_code */
219 srlx %o1, PAGE_SHIFT, %o1
220 andcc %o3, FAULT_CODE_DTLB, %g0
221 sllx %o1, PAGE_SHIFT, %o5
222 bne,pt %xcc, __prefill_dtlb
223 or %o5, %o0, %o5
224 ba,a,pt %xcc, __prefill_itlb
225
226 /* Cheetah specific versions, patched at boot time.
227 *
228 * This writes of the PRIMARY_CONTEXT register in this file are
229 * safe even on Cheetah+ and later wrt. the page size fields.
230 * The nucleus page size fields do not matter because we make
231 * no data references, and these instructions execute out of a
232 * locked I-TLB entry sitting in the fully assosciative I-TLB.
233 * This sequence should also never trap.
234 */
235__cheetah_flush_tlb_mm: /* 15 insns */
236 rdpr %pstate, %g7
237 andn %g7, PSTATE_IE, %g2
238 wrpr %g2, 0x0, %pstate
239 wrpr %g0, 1, %tl
240 mov PRIMARY_CONTEXT, %o2
241 mov 0x40, %g3
242 ldxa [%o2] ASI_DMMU, %g2
243 stxa %o0, [%o2] ASI_DMMU
244 stxa %g0, [%g3] ASI_DMMU_DEMAP
245 stxa %g0, [%g3] ASI_IMMU_DEMAP
246 stxa %g2, [%o2] ASI_DMMU
247 flush %g6
248 wrpr %g0, 0, %tl
249 retl
250 wrpr %g7, 0x0, %pstate
251
252__cheetah_flush_tlb_pending: /* 22 insns */
253 /* %o0 = context, %o1 = nr, %o2 = vaddrs[] */
254 rdpr %pstate, %g7
255 sllx %o1, 3, %o1
256 andn %g7, PSTATE_IE, %g2
257 wrpr %g2, 0x0, %pstate
258 wrpr %g0, 1, %tl
259 mov PRIMARY_CONTEXT, %o4
260 ldxa [%o4] ASI_DMMU, %g2
261 stxa %o0, [%o4] ASI_DMMU
2621: sub %o1, (1 << 3), %o1
263 ldx [%o2 + %o1], %o3
264 andcc %o3, 1, %g0
265 be,pn %icc, 2f
266 andn %o3, 1, %o3
267 stxa %g0, [%o3] ASI_IMMU_DEMAP
2682: stxa %g0, [%o3] ASI_DMMU_DEMAP
b445e26c 269 membar #Sync
1da177e4 270 brnz,pt %o1, 1b
b445e26c 271 nop
1da177e4
LT
272 stxa %g2, [%o4] ASI_DMMU
273 flush %g6
274 wrpr %g0, 0, %tl
275 retl
276 wrpr %g7, 0x0, %pstate
277
278#ifdef DCACHE_ALIASING_POSSIBLE
279flush_dcpage_cheetah: /* 11 insns */
280 sethi %uhi(PAGE_OFFSET), %g1
281 sllx %g1, 32, %g1
282 sub %o0, %g1, %o0
283 sethi %hi(PAGE_SIZE), %o4
2841: subcc %o4, (1 << 5), %o4
285 stxa %g0, [%o0 + %o4] ASI_DCACHE_INVALIDATE
286 membar #Sync
287 bne,pt %icc, 1b
288 nop
289 retl /* I-cache flush never needed on Cheetah, see callers. */
290 nop
291#endif /* DCACHE_ALIASING_POSSIBLE */
292
293cheetah_patch_one:
2941: lduw [%o1], %g1
295 stw %g1, [%o0]
296 flush %o0
297 subcc %o2, 1, %o2
298 add %o1, 4, %o1
299 bne,pt %icc, 1b
300 add %o0, 4, %o0
301 retl
302 nop
303
304 .globl cheetah_patch_cachetlbops
305cheetah_patch_cachetlbops:
306 save %sp, -128, %sp
307
308 sethi %hi(__flush_tlb_mm), %o0
309 or %o0, %lo(__flush_tlb_mm), %o0
310 sethi %hi(__cheetah_flush_tlb_mm), %o1
311 or %o1, %lo(__cheetah_flush_tlb_mm), %o1
312 call cheetah_patch_one
313 mov 15, %o2
314
315 sethi %hi(__flush_tlb_pending), %o0
316 or %o0, %lo(__flush_tlb_pending), %o0
317 sethi %hi(__cheetah_flush_tlb_pending), %o1
318 or %o1, %lo(__cheetah_flush_tlb_pending), %o1
319 call cheetah_patch_one
320 mov 22, %o2
321
322#ifdef DCACHE_ALIASING_POSSIBLE
323 sethi %hi(__flush_dcache_page), %o0
324 or %o0, %lo(__flush_dcache_page), %o0
325 sethi %hi(flush_dcpage_cheetah), %o1
326 or %o1, %lo(flush_dcpage_cheetah), %o1
327 call cheetah_patch_one
328 mov 11, %o2
329#endif /* DCACHE_ALIASING_POSSIBLE */
330
331 ret
332 restore
333
334#ifdef CONFIG_SMP
335 /* These are all called by the slaves of a cross call, at
336 * trap level 1, with interrupts fully disabled.
337 *
338 * Register usage:
339 * %g5 mm->context (all tlb flushes)
340 * %g1 address arg 1 (tlb page and range flushes)
341 * %g7 address arg 2 (tlb range flush only)
342 *
343 * %g6 ivector table, don't touch
344 * %g2 scratch 1
345 * %g3 scratch 2
346 * %g4 scratch 3
347 *
348 * TODO: Make xcall TLB range flushes use the tricks above... -DaveM
349 */
350 .align 32
351 .globl xcall_flush_tlb_mm
352xcall_flush_tlb_mm:
353 mov PRIMARY_CONTEXT, %g2
354 mov 0x40, %g4
355 ldxa [%g2] ASI_DMMU, %g3
356 stxa %g5, [%g2] ASI_DMMU
357 stxa %g0, [%g4] ASI_DMMU_DEMAP
358 stxa %g0, [%g4] ASI_IMMU_DEMAP
359 stxa %g3, [%g2] ASI_DMMU
360 retry
361
362 .globl xcall_flush_tlb_pending
363xcall_flush_tlb_pending:
364 /* %g5=context, %g1=nr, %g7=vaddrs[] */
365 sllx %g1, 3, %g1
366 mov PRIMARY_CONTEXT, %g4
367 ldxa [%g4] ASI_DMMU, %g2
368 stxa %g5, [%g4] ASI_DMMU
3691: sub %g1, (1 << 3), %g1
370 ldx [%g7 + %g1], %g5
371 andcc %g5, 0x1, %g0
372 be,pn %icc, 2f
373
374 andn %g5, 0x1, %g5
375 stxa %g0, [%g5] ASI_IMMU_DEMAP
3762: stxa %g0, [%g5] ASI_DMMU_DEMAP
377 membar #Sync
378 brnz,pt %g1, 1b
379 nop
380 stxa %g2, [%g4] ASI_DMMU
381 retry
382
383 .globl xcall_flush_tlb_kernel_range
384xcall_flush_tlb_kernel_range:
385 sethi %hi(PAGE_SIZE - 1), %g2
386 or %g2, %lo(PAGE_SIZE - 1), %g2
387 andn %g1, %g2, %g1
388 andn %g7, %g2, %g7
389 sub %g7, %g1, %g3
390 add %g2, 1, %g2
391 sub %g3, %g2, %g3
392 or %g1, 0x20, %g1 ! Nucleus
3931: stxa %g0, [%g1 + %g3] ASI_DMMU_DEMAP
394 stxa %g0, [%g1 + %g3] ASI_IMMU_DEMAP
395 membar #Sync
396 brnz,pt %g3, 1b
397 sub %g3, %g2, %g3
398 retry
399 nop
400 nop
401
402 /* This runs in a very controlled environment, so we do
403 * not need to worry about BH races etc.
404 */
405 .globl xcall_sync_tick
406xcall_sync_tick:
407 rdpr %pstate, %g2
408 wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
409 rdpr %pil, %g2
410 wrpr %g0, 15, %pil
411 sethi %hi(109f), %g7
412 b,pt %xcc, etrap_irq
413109: or %g7, %lo(109b), %g7
414 call smp_synchronize_tick_client
415 nop
416 clr %l6
417 b rtrap_xcall
418 ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
419
420 /* NOTE: This is SPECIAL!! We do etrap/rtrap however
421 * we choose to deal with the "BH's run with
422 * %pil==15" problem (described in asm/pil.h)
423 * by just invoking rtrap directly past where
424 * BH's are checked for.
425 *
426 * We do it like this because we do not want %pil==15
427 * lockups to prevent regs being reported.
428 */
429 .globl xcall_report_regs
430xcall_report_regs:
431 rdpr %pstate, %g2
432 wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
433 rdpr %pil, %g2
434 wrpr %g0, 15, %pil
435 sethi %hi(109f), %g7
436 b,pt %xcc, etrap_irq
437109: or %g7, %lo(109b), %g7
438 call __show_regs
439 add %sp, PTREGS_OFF, %o0
440 clr %l6
441 /* Has to be a non-v9 branch due to the large distance. */
442 b rtrap_xcall
443 ldx [%sp + PTREGS_OFF + PT_V9_TSTATE], %l1
444
445#ifdef DCACHE_ALIASING_POSSIBLE
446 .align 32
447 .globl xcall_flush_dcache_page_cheetah
448xcall_flush_dcache_page_cheetah: /* %g1 == physical page address */
449 sethi %hi(PAGE_SIZE), %g3
4501: subcc %g3, (1 << 5), %g3
451 stxa %g0, [%g1 + %g3] ASI_DCACHE_INVALIDATE
452 membar #Sync
453 bne,pt %icc, 1b
454 nop
455 retry
456 nop
457#endif /* DCACHE_ALIASING_POSSIBLE */
458
459 .globl xcall_flush_dcache_page_spitfire
460xcall_flush_dcache_page_spitfire: /* %g1 == physical page address
461 %g7 == kernel page virtual address
462 %g5 == (page->mapping != NULL) */
463#ifdef DCACHE_ALIASING_POSSIBLE
464 srlx %g1, (13 - 2), %g1 ! Form tag comparitor
465 sethi %hi(L1DCACHE_SIZE), %g3 ! D$ size == 16K
466 sub %g3, (1 << 5), %g3 ! D$ linesize == 32
4671: ldxa [%g3] ASI_DCACHE_TAG, %g2
468 andcc %g2, 0x3, %g0
469 be,pn %xcc, 2f
470 andn %g2, 0x3, %g2
471 cmp %g2, %g1
472
473 bne,pt %xcc, 2f
474 nop
475 stxa %g0, [%g3] ASI_DCACHE_TAG
476 membar #Sync
4772: cmp %g3, 0
478 bne,pt %xcc, 1b
479 sub %g3, (1 << 5), %g3
480
481 brz,pn %g5, 2f
482#endif /* DCACHE_ALIASING_POSSIBLE */
483 sethi %hi(PAGE_SIZE), %g3
484
4851: flush %g7
486 subcc %g3, (1 << 5), %g3
487 bne,pt %icc, 1b
488 add %g7, (1 << 5), %g7
489
4902: retry
491 nop
492 nop
493
494 .globl xcall_promstop
495xcall_promstop:
496 rdpr %pstate, %g2
497 wrpr %g2, PSTATE_IG | PSTATE_AG, %pstate
498 rdpr %pil, %g2
499 wrpr %g0, 15, %pil
500 sethi %hi(109f), %g7
501 b,pt %xcc, etrap_irq
502109: or %g7, %lo(109b), %g7
503 flushw
504 call prom_stopself
505 nop
506 /* We should not return, just spin if we do... */
5071: b,a,pt %xcc, 1b
508 nop
509
510 .data
511
512errata32_hwbug:
513 .xword 0
514
515 .text
516
517 /* These two are not performance critical... */
518 .globl xcall_flush_tlb_all_spitfire
519xcall_flush_tlb_all_spitfire:
520 /* Spitfire Errata #32 workaround. */
521 sethi %hi(errata32_hwbug), %g4
522 stx %g0, [%g4 + %lo(errata32_hwbug)]
523
524 clr %g2
525 clr %g3
5261: ldxa [%g3] ASI_DTLB_DATA_ACCESS, %g4
527 and %g4, _PAGE_L, %g5
528 brnz,pn %g5, 2f
529 mov TLB_TAG_ACCESS, %g7
530
531 stxa %g0, [%g7] ASI_DMMU
532 membar #Sync
533 stxa %g0, [%g3] ASI_DTLB_DATA_ACCESS
534 membar #Sync
535
536 /* Spitfire Errata #32 workaround. */
537 sethi %hi(errata32_hwbug), %g4
538 stx %g0, [%g4 + %lo(errata32_hwbug)]
539
5402: ldxa [%g3] ASI_ITLB_DATA_ACCESS, %g4
541 and %g4, _PAGE_L, %g5
542 brnz,pn %g5, 2f
543 mov TLB_TAG_ACCESS, %g7
544
545 stxa %g0, [%g7] ASI_IMMU
546 membar #Sync
547 stxa %g0, [%g3] ASI_ITLB_DATA_ACCESS
548 membar #Sync
549
550 /* Spitfire Errata #32 workaround. */
551 sethi %hi(errata32_hwbug), %g4
552 stx %g0, [%g4 + %lo(errata32_hwbug)]
553
5542: add %g2, 1, %g2
555 cmp %g2, SPITFIRE_HIGHEST_LOCKED_TLBENT
556 ble,pt %icc, 1b
557 sll %g2, 3, %g3
558 flush %g6
559 retry
560
561 .globl xcall_flush_tlb_all_cheetah
562xcall_flush_tlb_all_cheetah:
563 mov 0x80, %g2
564 stxa %g0, [%g2] ASI_DMMU_DEMAP
565 stxa %g0, [%g2] ASI_IMMU_DEMAP
566 retry
567
568 /* These just get rescheduled to PIL vectors. */
569 .globl xcall_call_function
570xcall_call_function:
571 wr %g0, (1 << PIL_SMP_CALL_FUNC), %set_softint
572 retry
573
574 .globl xcall_receive_signal
575xcall_receive_signal:
576 wr %g0, (1 << PIL_SMP_RECEIVE_SIGNAL), %set_softint
577 retry
578
579 .globl xcall_capture
580xcall_capture:
581 wr %g0, (1 << PIL_SMP_CAPTURE), %set_softint
582 retry
583
584#endif /* CONFIG_SMP */