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