[SPARC64]: Implement sun4v TSB miss handlers.
[powerpc.git] / 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
8         .text
9         .align  32
10
11         /* Invoked from TLB miss handler, we are in the
12          * MMU global registers and they are setup like
13          * this:
14          *
15          * %g1: TSB entry pointer
16          * %g2: available temporary
17          * %g3: FAULT_CODE_{D,I}TLB
18          * %g4: available temporary
19          * %g5: available temporary
20          * %g6: TAG TARGET
21          * %g7: available temporary, will be loaded by us with
22          *      the physical address base of the linux page
23          *      tables for the current address space
24          */
25 tsb_miss_dtlb:
26         mov             TLB_TAG_ACCESS, %g4
27         ldxa            [%g4] ASI_DMMU, %g4
28         ba,pt           %xcc, tsb_miss_page_table_walk
29          nop
30
31 tsb_miss_itlb:
32         mov             TLB_TAG_ACCESS, %g4
33         ldxa            [%g4] ASI_IMMU, %g4
34         ba,pt           %xcc, tsb_miss_page_table_walk
35          nop
36
37         /* The sun4v TLB miss handlers jump directly here instead
38          * of tsb_miss_{d,i}tlb with registers setup as follows:
39          *
40          * %g4: missing virtual address
41          * %g1: TSB entry address loaded
42          * %g6: TAG TARGET ((vaddr >> 22) | (ctx << 48))
43          */
44 tsb_miss_page_table_walk:
45         TRAP_LOAD_PGD_PHYS(%g7, %g5)
46
47         USER_PGTABLE_WALK_TL1(%g4, %g7, %g5, %g2, tsb_do_fault)
48
49 tsb_reload:
50         TSB_LOCK_TAG(%g1, %g2, %g7)
51
52         /* Load and check PTE.  */
53         ldxa            [%g5] ASI_PHYS_USE_EC, %g5
54         brgez,a,pn      %g5, tsb_do_fault
55          TSB_STORE(%g1, %g0)
56
57         /* If it is larger than the base page size, don't
58          * bother putting it into the TSB.
59          */
60         srlx            %g5, 32, %g2
61         sethi           %hi(_PAGE_ALL_SZ_BITS >> 32), %g7
62         and             %g2, %g7, %g2
63         sethi           %hi(_PAGE_SZBITS >> 32), %g7
64         cmp             %g2, %g7
65         bne,a,pn        %xcc, tsb_tlb_reload
66          TSB_STORE(%g1, %g0)
67
68         TSB_WRITE(%g1, %g5, %g6)
69
70         /* Finally, load TLB and return from trap.  */
71 tsb_tlb_reload:
72         cmp             %g3, FAULT_CODE_DTLB
73         bne,pn          %xcc, tsb_itlb_load
74          nop
75
76 tsb_dtlb_load:
77
78 661:    stxa            %g5, [%g0] ASI_DTLB_DATA_IN
79         retry
80         .section        .sun4v_2insn_patch, "ax"
81         .word           661b
82         nop
83         nop
84         .previous
85
86         /* For sun4v the ASI_DTLB_DATA_IN store and the retry
87          * instruction get nop'd out and we get here to branch
88          * to the sun4v tlb load code.  The registers are setup
89          * as follows:
90          *
91          * %g4: vaddr
92          * %g5: PTE
93          * %g6: TAG
94          *
95          * The sun4v TLB load wants the PTE in %g3 so we fix that
96          * up here.
97          */
98         ba,pt           %xcc, sun4v_dtlb_load
99          mov            %g5, %g3
100
101 tsb_itlb_load:
102
103 661:    stxa            %g5, [%g0] ASI_ITLB_DATA_IN
104         retry
105         .section        .sun4v_2insn_patch, "ax"
106         .word           661b
107         nop
108         nop
109         .previous
110
111         /* For sun4v the ASI_ITLB_DATA_IN store and the retry
112          * instruction get nop'd out and we get here to branch
113          * to the sun4v tlb load code.  The registers are setup
114          * as follows:
115          *
116          * %g4: vaddr
117          * %g5: PTE
118          * %g6: TAG
119          *
120          * The sun4v TLB load wants the PTE in %g3 so we fix that
121          * up here.
122          */
123         ba,pt           %xcc, sun4v_itlb_load
124          mov            %g5, %g3
125
126         /* No valid entry in the page tables, do full fault
127          * processing.
128          */
129
130         .globl          tsb_do_fault
131 tsb_do_fault:
132         cmp             %g3, FAULT_CODE_DTLB
133
134 661:    rdpr            %pstate, %g5
135         wrpr            %g5, PSTATE_AG | PSTATE_MG, %pstate
136         .section        .sun4v_2insn_patch, "ax"
137         .word           661b
138         nop
139         nop
140         .previous
141
142         bne,pn          %xcc, tsb_do_itlb_fault
143          nop
144
145 tsb_do_dtlb_fault:
146         rdpr    %tl, %g3
147         cmp     %g3, 1
148
149 661:    mov     TLB_TAG_ACCESS, %g4
150         ldxa    [%g4] ASI_DMMU, %g5
151         .section .sun4v_2insn_patch, "ax"
152         .word   661b
153         mov     %g4, %g5
154         nop
155         .previous
156
157         be,pt   %xcc, sparc64_realfault_common
158          mov    FAULT_CODE_DTLB, %g4
159         ba,pt   %xcc, winfix_trampoline
160          nop
161
162 tsb_do_itlb_fault:
163         rdpr    %tpc, %g5
164         ba,pt   %xcc, sparc64_realfault_common
165          mov    FAULT_CODE_ITLB, %g4
166
167         .globl  sparc64_realfault_common
168 sparc64_realfault_common:
169         /* fault code in %g4, fault address in %g5, etrap will
170          * preserve these two values in %l4 and %l5 respectively
171          */
172         ba,pt   %xcc, etrap                     ! Save trap state
173 1:       rd     %pc, %g7                        ! ...
174         stb     %l4, [%g6 + TI_FAULT_CODE]      ! Save fault code
175         stx     %l5, [%g6 + TI_FAULT_ADDR]      ! Save fault address
176         call    do_sparc64_fault                ! Call fault handler
177          add    %sp, PTREGS_OFF, %o0            ! Compute pt_regs arg
178         ba,pt   %xcc, rtrap_clr_l6              ! Restore cpu state
179          nop                                    ! Delay slot (fill me)
180
181 winfix_trampoline:
182         rdpr    %tpc, %g3                       ! Prepare winfixup TNPC
183         or      %g3, 0x7c, %g3                  ! Compute branch offset
184         wrpr    %g3, %tnpc                      ! Write it into TNPC
185         done                                    ! Trap return
186
187         /* Insert an entry into the TSB.
188          *
189          * %o0: TSB entry pointer (virt or phys address)
190          * %o1: tag
191          * %o2: pte
192          */
193         .align  32
194         .globl  __tsb_insert
195 __tsb_insert:
196         rdpr    %pstate, %o5
197         wrpr    %o5, PSTATE_IE, %pstate
198         TSB_LOCK_TAG(%o0, %g2, %g3)
199         TSB_WRITE(%o0, %o2, %o1)
200         wrpr    %o5, %pstate
201         retl
202          nop
203
204         /* Flush the given TSB entry if it has the matching
205          * tag.
206          *
207          * %o0: TSB entry pointer (virt or phys address)
208          * %o1: tag
209          */
210         .align  32
211         .globl  tsb_flush
212 tsb_flush:
213         sethi   %hi(TSB_TAG_LOCK_HIGH), %g2
214 1:      TSB_LOAD_TAG(%o0, %g1)
215         srlx    %g1, 32, %o3
216         andcc   %o3, %g2, %g0
217         bne,pn  %icc, 1b
218          membar #LoadLoad
219         cmp     %g1, %o1
220         bne,pt  %xcc, 2f
221          clr    %o3
222         TSB_CAS_TAG(%o0, %g1, %o3)
223         cmp     %g1, %o3
224         bne,pn  %xcc, 1b
225          nop
226 2:      retl
227          TSB_MEMBAR
228
229         /* Reload MMU related context switch state at
230          * schedule() time.
231          *
232          * %o0: page table physical address
233          * %o1: TSB register value
234          * %o2: TSB virtual address
235          * %o3: TSB mapping locked PTE
236          *
237          * We have to run this whole thing with interrupts
238          * disabled so that the current cpu doesn't change
239          * due to preemption.
240          */
241         .align  32
242         .globl  __tsb_context_switch
243 __tsb_context_switch:
244         rdpr    %pstate, %o5
245         wrpr    %o5, PSTATE_IE, %pstate
246
247         ldub    [%g6 + TI_CPU], %g1
248         sethi   %hi(trap_block), %g2
249         sllx    %g1, TRAP_BLOCK_SZ_SHIFT, %g1
250         or      %g2, %lo(trap_block), %g2
251         add     %g2, %g1, %g2
252         stx     %o0, [%g2 + TRAP_PER_CPU_PGD_PADDR]
253
254 661:    mov     TSB_REG, %g1
255         stxa    %o1, [%g1] ASI_DMMU
256         .section .sun4v_2insn_patch, "ax"
257         .word   661b
258         mov     SCRATCHPAD_UTSBREG1, %g1
259         stxa    %o1, [%g1] ASI_SCRATCHPAD
260         .previous
261
262         membar  #Sync
263
264 661:    stxa    %o1, [%g1] ASI_IMMU
265         membar  #Sync
266         .section .sun4v_2insn_patch, "ax"
267         .word   661b
268         nop
269         nop
270         .previous
271
272         brz     %o2, 9f
273          nop
274
275         sethi   %hi(sparc64_highest_unlocked_tlb_ent), %o4
276         mov     TLB_TAG_ACCESS, %g1
277         lduw    [%o4 + %lo(sparc64_highest_unlocked_tlb_ent)], %g2
278         stxa    %o2, [%g1] ASI_DMMU
279         membar  #Sync
280         sllx    %g2, 3, %g2
281         stxa    %o3, [%g2] ASI_DTLB_DATA_ACCESS
282         membar  #Sync
283 9:
284         wrpr    %o5, %pstate
285
286         retl
287          nop