Merge branch 'linus'
[linux-2.6] / arch / sparc64 / kernel / tsb.S
1 /* tsb.S: Sparc64 TSB table handling.
2  *
3  * Copyright (C) 2006 David S. Miller <davem@davemloft.net>
4  */
5
6 #include <asm/tsb.h>
7 #include <asm/hypervisor.h>
8
9         .text
10         .align  32
11
12         /* Invoked from TLB miss handler, we are in the
13          * MMU global registers and they are setup like
14          * this:
15          *
16          * %g1: TSB entry pointer
17          * %g2: available temporary
18          * %g3: FAULT_CODE_{D,I}TLB
19          * %g4: available temporary
20          * %g5: available temporary
21          * %g6: TAG TARGET
22          * %g7: available temporary, will be loaded by us with
23          *      the physical address base of the linux page
24          *      tables for the current address space
25          */
26 tsb_miss_dtlb:
27         mov             TLB_TAG_ACCESS, %g4
28         ba,pt           %xcc, tsb_miss_page_table_walk
29          ldxa           [%g4] ASI_DMMU, %g4
30
31 tsb_miss_itlb:
32         mov             TLB_TAG_ACCESS, %g4
33         ba,pt           %xcc, tsb_miss_page_table_walk
34          ldxa           [%g4] ASI_IMMU, %g4
35
36         /* At this point we have:
37          * %g1 --       TSB entry address
38          * %g3 --       FAULT_CODE_{D,I}TLB
39          * %g4 --       missing virtual address
40          * %g6 --       TAG TARGET (vaddr >> 22)
41          */
42 tsb_miss_page_table_walk:
43         TRAP_LOAD_PGD_PHYS(%g7, %g5)
44
45         /* And now we have the PGD base physical address in %g7.  */
46 tsb_miss_page_table_walk_sun4v_fastpath:
47         USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)
48
49         /* At this point we have:
50          * %g1 --       TSB entry address
51          * %g3 --       FAULT_CODE_{D,I}TLB
52          * %g5 --       physical address of PTE in Linux page tables
53          * %g6 --       TAG TARGET (vaddr >> 22)
54          */
55 tsb_reload:
56         TSB_LOCK_TAG(%g1, %g2, %g7)
57
58         /* Load and check PTE.  */
59         ldxa            [%g5] ASI_PHYS_USE_EC, %g5
60         mov             1, %g7
61         sllx            %g7, TSB_TAG_INVALID_BIT, %g7
62         brgez,a,pn      %g5, tsb_do_fault
63          TSB_STORE(%g1, %g7)
64
65         TSB_WRITE(%g1, %g5, %g6)
66
67         /* Finally, load TLB and return from trap.  */
68 tsb_tlb_reload:
69         cmp             %g3, FAULT_CODE_DTLB
70         bne,pn          %xcc, tsb_itlb_load
71          nop
72
73 tsb_dtlb_load:
74
75 661:    stxa            %g5, [%g0] ASI_DTLB_DATA_IN
76         retry
77         .section        .sun4v_2insn_patch, "ax"
78         .word           661b
79         nop
80         nop
81         .previous
82
83         /* For sun4v the ASI_DTLB_DATA_IN store and the retry
84          * instruction get nop'd out and we get here to branch
85          * to the sun4v tlb load code.  The registers are setup
86          * as follows:
87          *
88          * %g4: vaddr
89          * %g5: PTE
90          * %g6: TAG
91          *
92          * The sun4v TLB load wants the PTE in %g3 so we fix that
93          * up here.
94          */
95         ba,pt           %xcc, sun4v_dtlb_load
96          mov            %g5, %g3
97
98 tsb_itlb_load:
99         /* Executable bit must be set.  */
100 661:    andcc           %g5, _PAGE_EXEC_4U, %g0
101         .section        .sun4v_1insn_patch, "ax"
102         .word           661b
103         andcc           %g5, _PAGE_EXEC_4V, %g0
104         .previous
105
106         be,pn           %xcc, tsb_do_fault
107          nop
108
109 661:    stxa            %g5, [%g0] ASI_ITLB_DATA_IN
110         retry
111         .section        .sun4v_2insn_patch, "ax"
112         .word           661b
113         nop
114         nop
115         .previous
116
117         /* For sun4v the ASI_ITLB_DATA_IN store and the retry
118          * instruction get nop'd out and we get here to branch
119          * to the sun4v tlb load code.  The registers are setup
120          * as follows:
121          *
122          * %g4: vaddr
123          * %g5: PTE
124          * %g6: TAG
125          *
126          * The sun4v TLB load wants the PTE in %g3 so we fix that
127          * up here.
128          */
129         ba,pt           %xcc, sun4v_itlb_load
130          mov            %g5, %g3
131
132         /* No valid entry in the page tables, do full fault
133          * processing.
134          */
135
136         .globl          tsb_do_fault
137 tsb_do_fault:
138         cmp             %g3, FAULT_CODE_DTLB
139
140 661:    rdpr            %pstate, %g5
141         wrpr            %g5, PSTATE_AG | PSTATE_MG, %pstate
142         .section        .sun4v_2insn_patch, "ax"
143         .word           661b
144         SET_GL(1)
145         ldxa            [%g0] ASI_SCRATCHPAD, %g4
146         .previous
147
148         bne,pn          %xcc, tsb_do_itlb_fault
149          nop
150
151 tsb_do_dtlb_fault:
152         rdpr    %tl, %g3
153         cmp     %g3, 1
154
155 661:    mov     TLB_TAG_ACCESS, %g4
156         ldxa    [%g4] ASI_DMMU, %g5
157         .section .sun4v_2insn_patch, "ax"
158         .word   661b
159         ldx     [%g4 + HV_FAULT_D_ADDR_OFFSET], %g5
160         nop
161         .previous
162
163         be,pt   %xcc, sparc64_realfault_common
164          mov    FAULT_CODE_DTLB, %g4
165         ba,pt   %xcc, winfix_trampoline
166          nop
167
168 tsb_do_itlb_fault:
169         rdpr    %tpc, %g5
170         ba,pt   %xcc, sparc64_realfault_common
171          mov    FAULT_CODE_ITLB, %g4
172
173         .globl  sparc64_realfault_common
174 sparc64_realfault_common:
175         /* fault code in %g4, fault address in %g5, etrap will
176          * preserve these two values in %l4 and %l5 respectively
177          */
178         ba,pt   %xcc, etrap                     ! Save trap state
179 1:       rd     %pc, %g7                        ! ...
180         stb     %l4, [%g6 + TI_FAULT_CODE]      ! Save fault code
181         stx     %l5, [%g6 + TI_FAULT_ADDR]      ! Save fault address
182         call    do_sparc64_fault                ! Call fault handler
183          add    %sp, PTREGS_OFF, %o0            ! Compute pt_regs arg
184         ba,pt   %xcc, rtrap_clr_l6              ! Restore cpu state
185          nop                                    ! Delay slot (fill me)
186
187 winfix_trampoline:
188         rdpr    %tpc, %g3                       ! Prepare winfixup TNPC
189         or      %g3, 0x7c, %g3                  ! Compute branch offset
190         wrpr    %g3, %tnpc                      ! Write it into TNPC
191         done                                    ! Trap return
192
193         /* Insert an entry into the TSB.
194          *
195          * %o0: TSB entry pointer (virt or phys address)
196          * %o1: tag
197          * %o2: pte
198          */
199         .align  32
200         .globl  __tsb_insert
201 __tsb_insert:
202         rdpr    %pstate, %o5
203         wrpr    %o5, PSTATE_IE, %pstate
204         TSB_LOCK_TAG(%o0, %g2, %g3)
205         TSB_WRITE(%o0, %o2, %o1)
206         wrpr    %o5, %pstate
207         retl
208          nop
209         .size   __tsb_insert, .-__tsb_insert
210
211         /* Flush the given TSB entry if it has the matching
212          * tag.
213          *
214          * %o0: TSB entry pointer (virt or phys address)
215          * %o1: tag
216          */
217         .align  32
218         .globl  tsb_flush
219         .type   tsb_flush,#function
220 tsb_flush:
221         sethi   %hi(TSB_TAG_LOCK_HIGH), %g2
222 1:      TSB_LOAD_TAG(%o0, %g1)
223         srlx    %g1, 32, %o3
224         andcc   %o3, %g2, %g0
225         bne,pn  %icc, 1b
226          membar #LoadLoad
227         cmp     %g1, %o1
228         mov     1, %o3
229         bne,pt  %xcc, 2f
230          sllx   %o3, TSB_TAG_INVALID_BIT, %o3
231         TSB_CAS_TAG(%o0, %g1, %o3)
232         cmp     %g1, %o3
233         bne,pn  %xcc, 1b
234          nop
235 2:      retl
236          TSB_MEMBAR
237         .size   tsb_flush, .-tsb_flush
238
239         /* Reload MMU related context switch state at
240          * schedule() time.
241          *
242          * %o0: page table physical address
243          * %o1: TSB register value
244          * %o2: TSB virtual address
245          * %o3: TSB mapping locked PTE
246          * %o4: Hypervisor TSB descriptor physical address
247          *
248          * We have to run this whole thing with interrupts
249          * disabled so that the current cpu doesn't change
250          * due to preemption.
251          */
252         .align  32
253         .globl  __tsb_context_switch
254         .type   __tsb_context_switch,#function
255 __tsb_context_switch:
256         rdpr    %pstate, %o5
257         wrpr    %o5, PSTATE_IE, %pstate
258
259         ldub    [%g6 + TI_CPU], %g1
260         sethi   %hi(trap_block), %g2
261         sllx    %g1, TRAP_BLOCK_SZ_SHIFT, %g1
262         or      %g2, %lo(trap_block), %g2
263         add     %g2, %g1, %g2
264         stx     %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
265
266         sethi   %hi(tlb_type), %g1
267         lduw    [%g1 + %lo(tlb_type)], %g1
268         cmp     %g1, 3
269         bne,pt  %icc, 1f
270          nop
271
272         /* Hypervisor TSB switch. */
273         mov     SCRATCHPAD_UTSBREG1, %g1
274         stxa    %o1, [%g1] ASI_SCRATCHPAD
275         mov     -1, %g2
276         mov     SCRATCHPAD_UTSBREG2, %g1
277         stxa    %g2, [%g1] ASI_SCRATCHPAD
278
279         /* Save away %o5's %pstate, we have to use %o5 for
280          * the hypervisor call.
281          */
282         mov     %o5, %g1
283
284         mov     HV_FAST_MMU_TSB_CTXNON0, %o5
285         mov     1, %o0
286         mov     %o4, %o1
287         ta      HV_FAST_TRAP
288
289         /* Finish up and restore %o5.  */
290         ba,pt   %xcc, 9f
291          mov    %g1, %o5
292
293         /* SUN4U TSB switch.  */
294 1:      mov     TSB_REG, %g1
295         stxa    %o1, [%g1] ASI_DMMU
296         membar  #Sync
297         stxa    %o1, [%g1] ASI_IMMU
298         membar  #Sync
299
300 2:      brz     %o2, 9f
301          nop
302
303         sethi   %hi(sparc64_highest_unlocked_tlb_ent), %g2
304         mov     TLB_TAG_ACCESS, %g1
305         lduw    [%g2 + %lo(sparc64_highest_unlocked_tlb_ent)], %g2
306         stxa    %o2, [%g1] ASI_DMMU
307         membar  #Sync
308         sllx    %g2, 3, %g2
309         stxa    %o3, [%g2] ASI_DTLB_DATA_ACCESS
310         membar  #Sync
311 9:
312         wrpr    %o5, %pstate
313
314         retl
315          nop
316         .size   __tsb_context_switch, .-__tsb_context_switch
317
318 #define TSB_PASS_BITS   ((1 << TSB_TAG_LOCK_BIT) | \
319                          (1 << TSB_TAG_INVALID_BIT))
320
321         .align  32
322         .globl  copy_tsb
323         .type   copy_tsb,#function
324 copy_tsb:               /* %o0=old_tsb_base, %o1=old_tsb_size
325                          * %o2=new_tsb_base, %o3=new_tsb_size
326                          */
327         sethi           %uhi(TSB_PASS_BITS), %g7
328         srlx            %o3, 4, %o3
329         add             %o0, %o1, %g1   /* end of old tsb */
330         sllx            %g7, 32, %g7
331         sub             %o3, 1, %o3     /* %o3 == new tsb hash mask */
332
333 661:    prefetcha       [%o0] ASI_N, #one_read
334         .section        .tsb_phys_patch, "ax"
335         .word           661b
336         prefetcha       [%o0] ASI_PHYS_USE_EC, #one_read
337         .previous
338
339 90:     andcc           %o0, (64 - 1), %g0
340         bne             1f
341          add            %o0, 64, %o5
342
343 661:    prefetcha       [%o5] ASI_N, #one_read
344         .section        .tsb_phys_patch, "ax"
345         .word           661b
346         prefetcha       [%o5] ASI_PHYS_USE_EC, #one_read
347         .previous
348
349 1:      TSB_LOAD_QUAD(%o0, %g2)         /* %g2/%g3 == TSB entry */
350         andcc           %g2, %g7, %g0   /* LOCK or INVALID set? */
351         bne,pn          %xcc, 80f       /* Skip it */
352          sllx           %g2, 22, %o4    /* TAG --> VADDR */
353
354         /* This can definitely be computed faster... */
355         srlx            %o0, 4, %o5     /* Build index */
356         and             %o5, 511, %o5   /* Mask index */
357         sllx            %o5, PAGE_SHIFT, %o5 /* Put into vaddr position */
358         or              %o4, %o5, %o4   /* Full VADDR. */
359         srlx            %o4, PAGE_SHIFT, %o4 /* Shift down to create index */
360         and             %o4, %o3, %o4   /* Mask with new_tsb_nents-1 */
361         sllx            %o4, 4, %o4     /* Shift back up into tsb ent offset */
362         TSB_STORE(%o2 + %o4, %g2)       /* Store TAG */
363         add             %o4, 0x8, %o4   /* Advance to TTE */
364         TSB_STORE(%o2 + %o4, %g3)       /* Store TTE */
365
366 80:     add             %o0, 16, %o0
367         cmp             %o0, %g1
368         bne,pt          %xcc, 90b
369          nop
370
371         retl
372          TSB_MEMBAR
373         .size           copy_tsb, .-copy_tsb
374
375         /* Set the invalid bit in all TSB entries.  */
376         .align          32
377         .globl          tsb_init
378         .type           tsb_init,#function
379 tsb_init:               /* %o0 = TSB vaddr, %o1 = size in bytes */
380         prefetch        [%o0 + 0x000], #n_writes
381         mov             1, %g1
382         prefetch        [%o0 + 0x040], #n_writes
383         sllx            %g1, TSB_TAG_INVALID_BIT, %g1
384         prefetch        [%o0 + 0x080], #n_writes
385 1:      prefetch        [%o0 + 0x0c0], #n_writes
386         stx             %g1, [%o0 + 0x00]
387         stx             %g1, [%o0 + 0x10]
388         stx             %g1, [%o0 + 0x20]
389         stx             %g1, [%o0 + 0x30]
390         prefetch        [%o0 + 0x100], #n_writes
391         stx             %g1, [%o0 + 0x40]
392         stx             %g1, [%o0 + 0x50]
393         stx             %g1, [%o0 + 0x60]
394         stx             %g1, [%o0 + 0x70]
395         prefetch        [%o0 + 0x140], #n_writes
396         stx             %g1, [%o0 + 0x80]
397         stx             %g1, [%o0 + 0x90]
398         stx             %g1, [%o0 + 0xa0]
399         stx             %g1, [%o0 + 0xb0]
400         prefetch        [%o0 + 0x180], #n_writes
401         stx             %g1, [%o0 + 0xc0]
402         stx             %g1, [%o0 + 0xd0]
403         stx             %g1, [%o0 + 0xe0]
404         stx             %g1, [%o0 + 0xf0]
405         subcc           %o1, 0x100, %o1
406         bne,pt          %xcc, 1b
407          add            %o0, 0x100, %o0
408         retl
409          nop
410         nop
411         nop
412         .size           tsb_init, .-tsb_init
413
414         .globl          NGtsb_init
415         .type           NGtsb_init,#function
416 NGtsb_init:
417         rd              %asi, %g2
418         mov             1, %g1
419         wr              %g0, ASI_BLK_INIT_QUAD_LDD_P, %asi
420         sllx            %g1, TSB_TAG_INVALID_BIT, %g1
421 1:      stxa            %g1, [%o0 + 0x00] %asi
422         stxa            %g1, [%o0 + 0x10] %asi
423         stxa            %g1, [%o0 + 0x20] %asi
424         stxa            %g1, [%o0 + 0x30] %asi
425         stxa            %g1, [%o0 + 0x40] %asi
426         stxa            %g1, [%o0 + 0x50] %asi
427         stxa            %g1, [%o0 + 0x60] %asi
428         stxa            %g1, [%o0 + 0x70] %asi
429         stxa            %g1, [%o0 + 0x80] %asi
430         stxa            %g1, [%o0 + 0x90] %asi
431         stxa            %g1, [%o0 + 0xa0] %asi
432         stxa            %g1, [%o0 + 0xb0] %asi
433         stxa            %g1, [%o0 + 0xc0] %asi
434         stxa            %g1, [%o0 + 0xd0] %asi
435         stxa            %g1, [%o0 + 0xe0] %asi
436         stxa            %g1, [%o0 + 0xf0] %asi
437         subcc           %o1, 0x100, %o1
438         bne,pt          %xcc, 1b
439          add            %o0, 0x100, %o0
440         retl
441          wr             %g2, 0x0, %asi
442         .size           NGtsb_init, .-NGtsb_init