[SPARC64]: More TLB/TSB handling fixes.
[safe/jmp/linux-2.6] / arch / sparc64 / kernel / sun4v_tlb_miss.S
1 /* sun4v_tlb_miss.S: Sun4v TLB miss handlers.
2  *
3  * Copyright (C) 2006 <davem@davemloft.net>
4  */
5
6         .text
7         .align  32
8
9         /* Load ITLB fault information into VADDR and CTX, using BASE.  */
10 #define LOAD_ITLB_INFO(BASE, VADDR, CTX) \
11         ldx     [BASE + HV_FAULT_I_ADDR_OFFSET], VADDR; \
12         ldx     [BASE + HV_FAULT_I_CTX_OFFSET], CTX;
13
14         /* Load DTLB fault information into VADDR and CTX, using BASE.  */
15 #define LOAD_DTLB_INFO(BASE, VADDR, CTX) \
16         ldx     [BASE + HV_FAULT_D_ADDR_OFFSET], VADDR; \
17         ldx     [BASE + HV_FAULT_D_CTX_OFFSET], CTX;
18
19         /* DEST = (VADDR >> 22)
20          *
21          * Branch to ZERO_CTX_LABEL is context is zero.
22          */
23 #define COMPUTE_TAG_TARGET(DEST, VADDR, CTX, ZERO_CTX_LABEL) \
24         srlx    VADDR, 22, DEST; \
25         brz,pn  CTX, ZERO_CTX_LABEL; \
26          nop;
27
28         /* Create TSB pointer.  This is something like:
29          *
30          * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
31          * tsb_base = tsb_reg & ~0x7UL;
32          * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
33          * tsb_ptr = tsb_base + (tsb_index * 16);
34          */
35 #define COMPUTE_TSB_PTR(TSB_PTR, VADDR, TMP1, TMP2)     \
36         and     TSB_PTR, 0x7, TMP1;                     \
37         mov     512, TMP2;                              \
38         andn    TSB_PTR, 0x7, TSB_PTR;                  \
39         sllx    TMP2, TMP1, TMP2;                       \
40         srlx    VADDR, PAGE_SHIFT, TMP1;                \
41         sub     TMP2, 1, TMP2;                          \
42         and     TMP1, TMP2, TMP1;                       \
43         sllx    TMP1, 4, TMP1;                          \
44         add     TSB_PTR, TMP1, TSB_PTR;
45
46 sun4v_itlb_miss:
47         /* Load MMU Miss base into %g2.  */
48         ldxa    [%g0] ASI_SCRATCHPAD, %g2
49         
50         /* Load UTSB reg into %g1.  */
51         mov     SCRATCHPAD_UTSBREG1, %g1
52         ldxa    [%g1] ASI_SCRATCHPAD, %g1
53
54         LOAD_ITLB_INFO(%g2, %g4, %g5)
55         COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_itlb_4v)
56         COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
57
58         /* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
59         ldda    [%g1] ASI_QUAD_LDD_PHYS_4V, %g2
60         cmp     %g2, %g6
61         sethi   %hi(PAGE_EXEC), %g7
62         ldx     [%g7 + %lo(PAGE_EXEC)], %g7
63         bne,a,pn %xcc, tsb_miss_page_table_walk
64          mov    FAULT_CODE_ITLB, %g3
65         andcc   %g3, %g7, %g0
66         be,a,pn %xcc, tsb_do_fault
67          mov    FAULT_CODE_ITLB, %g3
68
69         /* We have a valid entry, make hypervisor call to load
70          * I-TLB and return from trap.
71          *
72          * %g3: PTE
73          * %g4: vaddr
74          */
75 sun4v_itlb_load:
76         ldxa    [%g0] ASI_SCRATCHPAD, %g6
77         mov     %o0, %g1                ! save %o0
78         mov     %o1, %g2                ! save %o1
79         mov     %o2, %g5                ! save %o2
80         mov     %o3, %g7                ! save %o3
81         mov     %g4, %o0                ! vaddr
82         ldx     [%g6 + HV_FAULT_I_CTX_OFFSET], %o1      ! ctx
83         mov     %g3, %o2                ! PTE
84         mov     HV_MMU_IMMU, %o3        ! flags
85         ta      HV_MMU_MAP_ADDR_TRAP
86         brnz,pn %o0, sun4v_itlb_error
87          mov    %g2, %o1                ! restore %o1
88         mov     %g1, %o0                ! restore %o0
89         mov     %g5, %o2                ! restore %o2
90         mov     %g7, %o3                ! restore %o3
91
92         retry
93
94 sun4v_dtlb_miss:
95         /* Load MMU Miss base into %g2.  */
96         ldxa    [%g0] ASI_SCRATCHPAD, %g2
97         
98         /* Load UTSB reg into %g1.  */
99         mov     SCRATCHPAD_UTSBREG1, %g1
100         ldxa    [%g1] ASI_SCRATCHPAD, %g1
101
102         LOAD_DTLB_INFO(%g2, %g4, %g5)
103         COMPUTE_TAG_TARGET(%g6, %g4, %g5, kvmap_dtlb_4v)
104         COMPUTE_TSB_PTR(%g1, %g4, %g3, %g7)
105
106         /* Load TSB tag/pte into %g2/%g3 and compare the tag.  */
107         ldda    [%g1] ASI_QUAD_LDD_PHYS_4V, %g2
108         cmp     %g2, %g6
109         bne,a,pn %xcc, tsb_miss_page_table_walk
110          mov    FAULT_CODE_ITLB, %g3
111
112         /* We have a valid entry, make hypervisor call to load
113          * D-TLB and return from trap.
114          *
115          * %g3: PTE
116          * %g4: vaddr
117          */
118 sun4v_dtlb_load:
119         ldxa    [%g0] ASI_SCRATCHPAD, %g6
120         mov     %o0, %g1                ! save %o0
121         mov     %o1, %g2                ! save %o1
122         mov     %o2, %g5                ! save %o2
123         mov     %o3, %g7                ! save %o3
124         mov     %g4, %o0                ! vaddr
125         ldx     [%g6 + HV_FAULT_D_CTX_OFFSET], %o1      ! ctx
126         mov     %g3, %o2                ! PTE
127         mov     HV_MMU_DMMU, %o3        ! flags
128         ta      HV_MMU_MAP_ADDR_TRAP
129         brnz,pn %o0, sun4v_dtlb_error
130          mov    %g2, %o1                ! restore %o1
131         mov     %g1, %o0                ! restore %o0
132         mov     %g5, %o2                ! restore %o2
133         mov     %g7, %o3                ! restore %o3
134
135         retry
136
137 sun4v_dtlb_prot:
138         SET_GL(1)
139
140         /* Load MMU Miss base into %g2.  */
141         ldxa    [%g0] ASI_SCRATCHPAD, %g5
142         
143         ldx     [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
144         rdpr    %tl, %g1
145         cmp     %g1, 1
146         bgu,pn  %xcc, winfix_trampoline
147          nop
148         ba,pt   %xcc, sparc64_realfault_common
149          mov    FAULT_CODE_DTLB | FAULT_CODE_WRITE, %g4
150
151         /* Called from trap table with TAG TARGET placed into
152          * %g6, SCRATCHPAD_UTSBREG1 contents in %g1, and
153          * SCRATCHPAD_MMU_MISS contents in %g2.
154          */
155 sun4v_itsb_miss:
156         mov     SCRATCHPAD_UTSBREG1, %g1
157         ldxa    [%g1] ASI_SCRATCHPAD, %g1
158         brz,pn  %g5, kvmap_itlb_4v
159          mov    FAULT_CODE_ITLB, %g3
160         ba,a,pt %xcc, sun4v_tsb_miss_common
161
162         /* Called from trap table with TAG TARGET placed into
163          * %g6 and SCRATCHPAD_UTSBREG1 contents in %g1.
164          */
165 sun4v_dtsb_miss:
166         mov     SCRATCHPAD_UTSBREG1, %g1
167         ldxa    [%g1] ASI_SCRATCHPAD, %g1
168         brz,pn  %g5, kvmap_dtlb_4v
169          mov    FAULT_CODE_DTLB, %g3
170
171         /* Create TSB pointer into %g1.  This is something like:
172          *
173          * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
174          * tsb_base = tsb_reg & ~0x7UL;
175          * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
176          * tsb_ptr = tsb_base + (tsb_index * 16);
177          */
178 sun4v_tsb_miss_common:
179         COMPUTE_TSB_PTR(%g1, %g4, %g5, %g7)
180
181         /* Branch directly to page table lookup.  We have SCRATCHPAD_MMU_MISS
182          * still in %g2, so it's quite trivial to get at the PGD PHYS value
183          * so we can preload it into %g7.
184          */
185         sub     %g2, TRAP_PER_CPU_FAULT_INFO, %g2
186         ba,pt   %xcc, tsb_miss_page_table_walk_sun4v_fastpath
187          ldx    [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
188
189 sun4v_itlb_error:
190         sethi   %hi(sun4v_err_itlb_vaddr), %g1
191         stx     %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
192         sethi   %hi(sun4v_err_itlb_ctx), %g1
193         ldxa    [%g0] ASI_SCRATCHPAD, %g6
194         ldx     [%g6 + HV_FAULT_I_CTX_OFFSET], %o1
195         stx     %o1, [%g1 + %lo(sun4v_err_itlb_ctx)]
196         sethi   %hi(sun4v_err_itlb_pte), %g1
197         stx     %g3, [%g1 + %lo(sun4v_err_itlb_pte)]
198         sethi   %hi(sun4v_err_itlb_error), %g1
199         stx     %o0, [%g1 + %lo(sun4v_err_itlb_error)]
200
201         rdpr    %tl, %g4
202         cmp     %g4, 1
203         ble,pt  %icc, 1f
204          sethi  %hi(2f), %g7
205         ba,pt   %xcc, etraptl1
206          or     %g7, %lo(2f), %g7
207
208 1:      ba,pt   %xcc, etrap
209 2:       or     %g7, %lo(2b), %g7
210         call    sun4v_itlb_error_report
211          add    %sp, PTREGS_OFF, %o0
212
213         /* NOTREACHED */
214
215 sun4v_dtlb_error:
216         sethi   %hi(sun4v_err_dtlb_vaddr), %g1
217         stx     %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
218         sethi   %hi(sun4v_err_dtlb_ctx), %g1
219         ldxa    [%g0] ASI_SCRATCHPAD, %g6
220         ldx     [%g6 + HV_FAULT_D_CTX_OFFSET], %o1
221         stx     %o1, [%g1 + %lo(sun4v_err_dtlb_ctx)]
222         sethi   %hi(sun4v_err_dtlb_pte), %g1
223         stx     %g3, [%g1 + %lo(sun4v_err_dtlb_pte)]
224         sethi   %hi(sun4v_err_dtlb_error), %g1
225         stx     %o0, [%g1 + %lo(sun4v_err_dtlb_error)]
226
227         rdpr    %tl, %g4
228         cmp     %g4, 1
229         ble,pt  %icc, 1f
230          sethi  %hi(2f), %g7
231         ba,pt   %xcc, etraptl1
232          or     %g7, %lo(2f), %g7
233
234 1:      ba,pt   %xcc, etrap
235 2:       or     %g7, %lo(2b), %g7
236         call    sun4v_dtlb_error_report
237          add    %sp, PTREGS_OFF, %o0
238
239         /* NOTREACHED */
240
241         /* Instruction Access Exception, tl0. */
242 sun4v_iacc:
243         ldxa    [%g0] ASI_SCRATCHPAD, %g2
244         ldx     [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
245         ldx     [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
246         ldx     [%g2 + HV_FAULT_I_CTX_OFFSET], %g5
247         sllx    %g3, 16, %g3
248         or      %g5, %g3, %g5
249         ba,pt   %xcc, etrap
250          rd     %pc, %g7
251         mov     %l4, %o1
252         mov     %l5, %o2
253         call    sun4v_insn_access_exception
254          add    %sp, PTREGS_OFF, %o0
255         ba,a,pt %xcc, rtrap_clr_l6
256
257         /* Instruction Access Exception, tl1. */
258 sun4v_iacc_tl1:
259         ldxa    [%g0] ASI_SCRATCHPAD, %g2
260         ldx     [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
261         ldx     [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
262         ldx     [%g2 + HV_FAULT_I_CTX_OFFSET], %g5
263         sllx    %g3, 16, %g3
264         or      %g5, %g3, %g5
265         ba,pt   %xcc, etraptl1
266          rd     %pc, %g7
267         mov     %l4, %o1
268         mov     %l5, %o2
269         call    sun4v_insn_access_exception_tl1
270          add    %sp, PTREGS_OFF, %o0
271         ba,a,pt %xcc, rtrap_clr_l6
272
273         /* Data Access Exception, tl0. */
274 sun4v_dacc:
275         ldxa    [%g0] ASI_SCRATCHPAD, %g2
276         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
277         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
278         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
279         sllx    %g3, 16, %g3
280         or      %g5, %g3, %g5
281         ba,pt   %xcc, etrap
282          rd     %pc, %g7
283         mov     %l4, %o1
284         mov     %l5, %o2
285         call    sun4v_data_access_exception
286          add    %sp, PTREGS_OFF, %o0
287         ba,a,pt %xcc, rtrap_clr_l6
288
289         /* Data Access Exception, tl1. */
290 sun4v_dacc_tl1:
291         ldxa    [%g0] ASI_SCRATCHPAD, %g2
292         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
293         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
294         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
295         sllx    %g3, 16, %g3
296         or      %g5, %g3, %g5
297         ba,pt   %xcc, etraptl1
298          rd     %pc, %g7
299         mov     %l4, %o1
300         mov     %l5, %o2
301         call    sun4v_data_access_exception_tl1
302          add    %sp, PTREGS_OFF, %o0
303         ba,a,pt %xcc, rtrap_clr_l6
304
305         /* Memory Address Unaligned.  */
306 sun4v_mna:
307         ldxa    [%g0] ASI_SCRATCHPAD, %g2
308         mov     HV_FAULT_TYPE_UNALIGNED, %g3
309         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
310         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
311         sllx    %g3, 16, %g3
312         or      %g5, %g3, %g5
313
314         /* Window fixup? */
315         rdpr    %tl, %g2
316         cmp     %g2, 1
317         bgu,pn  %icc, winfix_mna
318          rdpr   %tpc, %g3
319
320         ba,pt   %xcc, etrap
321          rd     %pc, %g7
322         mov     %l4, %o1
323         mov     %l5, %o2
324         call    sun4v_do_mna
325          add    %sp, PTREGS_OFF, %o0
326         ba,a,pt %xcc, rtrap_clr_l6
327
328         /* Privileged Action.  */
329 sun4v_privact:
330         ba,pt   %xcc, etrap
331          rd     %pc, %g7
332         call    do_privact
333          add    %sp, PTREGS_OFF, %o0
334         ba,a,pt %xcc, rtrap_clr_l6
335
336         /* Unaligned ldd float, tl0. */
337 sun4v_lddfmna:
338         ldxa    [%g0] ASI_SCRATCHPAD, %g2
339         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
340         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
341         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
342         sllx    %g3, 16, %g3
343         or      %g5, %g3, %g5
344         ba,pt   %xcc, etrap
345          rd     %pc, %g7
346         mov     %l4, %o1
347         mov     %l5, %o2
348         call    handle_lddfmna
349          add    %sp, PTREGS_OFF, %o0
350         ba,a,pt %xcc, rtrap_clr_l6
351
352         /* Unaligned std float, tl0. */
353 sun4v_stdfmna:
354         ldxa    [%g0] ASI_SCRATCHPAD, %g2
355         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
356         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
357         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
358         sllx    %g3, 16, %g3
359         or      %g5, %g3, %g5
360         ba,pt   %xcc, etrap
361          rd     %pc, %g7
362         mov     %l4, %o1
363         mov     %l5, %o2
364         call    handle_stdfmna
365          add    %sp, PTREGS_OFF, %o0
366         ba,a,pt %xcc, rtrap_clr_l6
367
368 #define BRANCH_ALWAYS   0x10680000
369 #define NOP             0x01000000
370 #define SUN4V_DO_PATCH(OLD, NEW)        \
371         sethi   %hi(NEW), %g1; \
372         or      %g1, %lo(NEW), %g1; \
373         sethi   %hi(OLD), %g2; \
374         or      %g2, %lo(OLD), %g2; \
375         sub     %g1, %g2, %g1; \
376         sethi   %hi(BRANCH_ALWAYS), %g3; \
377         sll     %g1, 11, %g1; \
378         srl     %g1, 11 + 2, %g1; \
379         or      %g3, %lo(BRANCH_ALWAYS), %g3; \
380         or      %g3, %g1, %g3; \
381         stw     %g3, [%g2]; \
382         sethi   %hi(NOP), %g3; \
383         or      %g3, %lo(NOP), %g3; \
384         stw     %g3, [%g2 + 0x4]; \
385         flush   %g2;
386
387         .globl  sun4v_patch_tlb_handlers
388         .type   sun4v_patch_tlb_handlers,#function
389 sun4v_patch_tlb_handlers:
390         SUN4V_DO_PATCH(tl0_iamiss, sun4v_itlb_miss)
391         SUN4V_DO_PATCH(tl1_iamiss, sun4v_itlb_miss)
392         SUN4V_DO_PATCH(tl0_damiss, sun4v_dtlb_miss)
393         SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss)
394         SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot)
395         SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot)
396         SUN4V_DO_PATCH(tl0_iax, sun4v_iacc)
397         SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1)
398         SUN4V_DO_PATCH(tl0_dax, sun4v_dacc)
399         SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1)
400         SUN4V_DO_PATCH(tl0_mna, sun4v_mna)
401         SUN4V_DO_PATCH(tl1_mna, sun4v_mna)
402         SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna)
403         SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna)
404         SUN4V_DO_PATCH(tl0_privact, sun4v_privact)
405         retl
406          nop
407         .size   sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers