]> err.no Git - linux-2.6/blob - arch/sparc64/kernel/sun4v_tlb_miss.S
[SPARC64]: Fix unaligned access winfxup handling on SUN4V.
[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 %g5.  */
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:
152          * %g4: vaddr
153          * %g5: context
154          * %g6: TAG TARGET
155          */
156 sun4v_itsb_miss:
157         mov     SCRATCHPAD_UTSBREG1, %g1
158         ldxa    [%g1] ASI_SCRATCHPAD, %g1
159         brz,pn  %g5, kvmap_itlb_4v
160          mov    FAULT_CODE_ITLB, %g3
161         ba,a,pt %xcc, sun4v_tsb_miss_common
162
163         /* Called from trap table:
164          * %g4: vaddr
165          * %g5: context
166          * %g6: TAG TARGET
167          */
168 sun4v_dtsb_miss:
169         mov     SCRATCHPAD_UTSBREG1, %g1
170         ldxa    [%g1] ASI_SCRATCHPAD, %g1
171         brz,pn  %g5, kvmap_dtlb_4v
172          mov    FAULT_CODE_DTLB, %g3
173
174         /* fallthrough */
175
176         /* Create TSB pointer into %g1.  This is something like:
177          *
178          * index_mask = (512 << (tsb_reg & 0x7UL)) - 1UL;
179          * tsb_base = tsb_reg & ~0x7UL;
180          * tsb_index = ((vaddr >> PAGE_SHIFT) & tsb_mask);
181          * tsb_ptr = tsb_base + (tsb_index * 16);
182          */
183 sun4v_tsb_miss_common:
184         COMPUTE_TSB_PTR(%g1, %g4, %g5, %g7)
185
186         /* Branch directly to page table lookup.  We have SCRATCHPAD_MMU_MISS
187          * still in %g2, so it's quite trivial to get at the PGD PHYS value
188          * so we can preload it into %g7.
189          */
190         sub     %g2, TRAP_PER_CPU_FAULT_INFO, %g2
191         ba,pt   %xcc, tsb_miss_page_table_walk_sun4v_fastpath
192          ldx    [%g2 + TRAP_PER_CPU_PGD_PADDR], %g7
193
194 sun4v_itlb_error:
195         sethi   %hi(sun4v_err_itlb_vaddr), %g1
196         stx     %g4, [%g1 + %lo(sun4v_err_itlb_vaddr)]
197         sethi   %hi(sun4v_err_itlb_ctx), %g1
198         ldxa    [%g0] ASI_SCRATCHPAD, %g6
199         ldx     [%g6 + HV_FAULT_I_CTX_OFFSET], %o1
200         stx     %o1, [%g1 + %lo(sun4v_err_itlb_ctx)]
201         sethi   %hi(sun4v_err_itlb_pte), %g1
202         stx     %g3, [%g1 + %lo(sun4v_err_itlb_pte)]
203         sethi   %hi(sun4v_err_itlb_error), %g1
204         stx     %o0, [%g1 + %lo(sun4v_err_itlb_error)]
205
206         rdpr    %tl, %g4
207         cmp     %g4, 1
208         ble,pt  %icc, 1f
209          sethi  %hi(2f), %g7
210         ba,pt   %xcc, etraptl1
211          or     %g7, %lo(2f), %g7
212
213 1:      ba,pt   %xcc, etrap
214 2:       or     %g7, %lo(2b), %g7
215         call    sun4v_itlb_error_report
216          add    %sp, PTREGS_OFF, %o0
217
218         /* NOTREACHED */
219
220 sun4v_dtlb_error:
221         sethi   %hi(sun4v_err_dtlb_vaddr), %g1
222         stx     %g4, [%g1 + %lo(sun4v_err_dtlb_vaddr)]
223         sethi   %hi(sun4v_err_dtlb_ctx), %g1
224         ldxa    [%g0] ASI_SCRATCHPAD, %g6
225         ldx     [%g6 + HV_FAULT_D_CTX_OFFSET], %o1
226         stx     %o1, [%g1 + %lo(sun4v_err_dtlb_ctx)]
227         sethi   %hi(sun4v_err_dtlb_pte), %g1
228         stx     %g3, [%g1 + %lo(sun4v_err_dtlb_pte)]
229         sethi   %hi(sun4v_err_dtlb_error), %g1
230         stx     %o0, [%g1 + %lo(sun4v_err_dtlb_error)]
231
232         rdpr    %tl, %g4
233         cmp     %g4, 1
234         ble,pt  %icc, 1f
235          sethi  %hi(2f), %g7
236         ba,pt   %xcc, etraptl1
237          or     %g7, %lo(2f), %g7
238
239 1:      ba,pt   %xcc, etrap
240 2:       or     %g7, %lo(2b), %g7
241         call    sun4v_dtlb_error_report
242          add    %sp, PTREGS_OFF, %o0
243
244         /* NOTREACHED */
245
246         /* Instruction Access Exception, tl0. */
247 sun4v_iacc:
248         ldxa    [%g0] ASI_SCRATCHPAD, %g2
249         ldx     [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
250         ldx     [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
251         ldx     [%g2 + HV_FAULT_I_CTX_OFFSET], %g5
252         sllx    %g3, 16, %g3
253         or      %g5, %g3, %g5
254         ba,pt   %xcc, etrap
255          rd     %pc, %g7
256         mov     %l4, %o1
257         mov     %l5, %o2
258         call    sun4v_insn_access_exception
259          add    %sp, PTREGS_OFF, %o0
260         ba,a,pt %xcc, rtrap_clr_l6
261
262         /* Instruction Access Exception, tl1. */
263 sun4v_iacc_tl1:
264         ldxa    [%g0] ASI_SCRATCHPAD, %g2
265         ldx     [%g2 + HV_FAULT_I_TYPE_OFFSET], %g3
266         ldx     [%g2 + HV_FAULT_I_ADDR_OFFSET], %g4
267         ldx     [%g2 + HV_FAULT_I_CTX_OFFSET], %g5
268         sllx    %g3, 16, %g3
269         or      %g5, %g3, %g5
270         ba,pt   %xcc, etraptl1
271          rd     %pc, %g7
272         mov     %l4, %o1
273         mov     %l5, %o2
274         call    sun4v_insn_access_exception_tl1
275          add    %sp, PTREGS_OFF, %o0
276         ba,a,pt %xcc, rtrap_clr_l6
277
278         /* Data Access Exception, tl0. */
279 sun4v_dacc:
280         ldxa    [%g0] ASI_SCRATCHPAD, %g2
281         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
282         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
283         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
284         sllx    %g3, 16, %g3
285         or      %g5, %g3, %g5
286         ba,pt   %xcc, etrap
287          rd     %pc, %g7
288         mov     %l4, %o1
289         mov     %l5, %o2
290         call    sun4v_data_access_exception
291          add    %sp, PTREGS_OFF, %o0
292         ba,a,pt %xcc, rtrap_clr_l6
293
294         /* Data Access Exception, tl1. */
295 sun4v_dacc_tl1:
296         ldxa    [%g0] ASI_SCRATCHPAD, %g2
297         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
298         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
299         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
300         sllx    %g3, 16, %g3
301         or      %g5, %g3, %g5
302         ba,pt   %xcc, etraptl1
303          rd     %pc, %g7
304         mov     %l4, %o1
305         mov     %l5, %o2
306         call    sun4v_data_access_exception_tl1
307          add    %sp, PTREGS_OFF, %o0
308         ba,a,pt %xcc, rtrap_clr_l6
309
310         /* Memory Address Unaligned.  */
311 sun4v_mna:
312         /* Window fixup? */
313         rdpr    %tl, %g2
314         cmp     %g2, 1
315         ble,pt  %icc, 1f
316          nop
317
318         SET_GL(1)
319         ldxa    [%g0] ASI_SCRATCHPAD, %g5
320         ldx     [%g5 + HV_FAULT_D_ADDR_OFFSET], %g5
321         mov     HV_FAULT_TYPE_UNALIGNED, %g3
322         ldx     [%g5 + HV_FAULT_D_CTX_OFFSET], %g4
323         sllx    %g3, 16, %g3
324         or      %g4, %g3, %g4
325         ba,pt   %xcc, winfix_mna
326          rdpr   %tpc, %g3
327         /* not reached */
328
329 1:      ldxa    [%g0] ASI_SCRATCHPAD, %g2
330         mov     HV_FAULT_TYPE_UNALIGNED, %g3
331         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
332         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
333         sllx    %g3, 16, %g3
334         or      %g5, %g3, %g5
335
336         ba,pt   %xcc, etrap
337          rd     %pc, %g7
338         mov     %l4, %o1
339         mov     %l5, %o2
340         call    sun4v_do_mna
341          add    %sp, PTREGS_OFF, %o0
342         ba,a,pt %xcc, rtrap_clr_l6
343
344         /* Privileged Action.  */
345 sun4v_privact:
346         ba,pt   %xcc, etrap
347          rd     %pc, %g7
348         call    do_privact
349          add    %sp, PTREGS_OFF, %o0
350         ba,a,pt %xcc, rtrap_clr_l6
351
352         /* Unaligned ldd float, tl0. */
353 sun4v_lddfmna:
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_lddfmna
365          add    %sp, PTREGS_OFF, %o0
366         ba,a,pt %xcc, rtrap_clr_l6
367
368         /* Unaligned std float, tl0. */
369 sun4v_stdfmna:
370         ldxa    [%g0] ASI_SCRATCHPAD, %g2
371         ldx     [%g2 + HV_FAULT_D_TYPE_OFFSET], %g3
372         ldx     [%g2 + HV_FAULT_D_ADDR_OFFSET], %g4
373         ldx     [%g2 + HV_FAULT_D_CTX_OFFSET], %g5
374         sllx    %g3, 16, %g3
375         or      %g5, %g3, %g5
376         ba,pt   %xcc, etrap
377          rd     %pc, %g7
378         mov     %l4, %o1
379         mov     %l5, %o2
380         call    handle_stdfmna
381          add    %sp, PTREGS_OFF, %o0
382         ba,a,pt %xcc, rtrap_clr_l6
383
384 #define BRANCH_ALWAYS   0x10680000
385 #define NOP             0x01000000
386 #define SUN4V_DO_PATCH(OLD, NEW)        \
387         sethi   %hi(NEW), %g1; \
388         or      %g1, %lo(NEW), %g1; \
389         sethi   %hi(OLD), %g2; \
390         or      %g2, %lo(OLD), %g2; \
391         sub     %g1, %g2, %g1; \
392         sethi   %hi(BRANCH_ALWAYS), %g3; \
393         sll     %g1, 11, %g1; \
394         srl     %g1, 11 + 2, %g1; \
395         or      %g3, %lo(BRANCH_ALWAYS), %g3; \
396         or      %g3, %g1, %g3; \
397         stw     %g3, [%g2]; \
398         sethi   %hi(NOP), %g3; \
399         or      %g3, %lo(NOP), %g3; \
400         stw     %g3, [%g2 + 0x4]; \
401         flush   %g2;
402
403         .globl  sun4v_patch_tlb_handlers
404         .type   sun4v_patch_tlb_handlers,#function
405 sun4v_patch_tlb_handlers:
406         SUN4V_DO_PATCH(tl0_iamiss, sun4v_itlb_miss)
407         SUN4V_DO_PATCH(tl1_iamiss, sun4v_itlb_miss)
408         SUN4V_DO_PATCH(tl0_damiss, sun4v_dtlb_miss)
409         SUN4V_DO_PATCH(tl1_damiss, sun4v_dtlb_miss)
410         SUN4V_DO_PATCH(tl0_daprot, sun4v_dtlb_prot)
411         SUN4V_DO_PATCH(tl1_daprot, sun4v_dtlb_prot)
412         SUN4V_DO_PATCH(tl0_iax, sun4v_iacc)
413         SUN4V_DO_PATCH(tl1_iax, sun4v_iacc_tl1)
414         SUN4V_DO_PATCH(tl0_dax, sun4v_dacc)
415         SUN4V_DO_PATCH(tl1_dax, sun4v_dacc_tl1)
416         SUN4V_DO_PATCH(tl0_mna, sun4v_mna)
417         SUN4V_DO_PATCH(tl1_mna, sun4v_mna)
418         SUN4V_DO_PATCH(tl0_lddfmna, sun4v_lddfmna)
419         SUN4V_DO_PATCH(tl0_stdfmna, sun4v_stdfmna)
420         SUN4V_DO_PATCH(tl0_privact, sun4v_privact)
421         retl
422          nop
423         .size   sun4v_patch_tlb_handlers,.-sun4v_patch_tlb_handlers