1 | /* SPDX-License-Identifier: GPL-2.0 */ |
2 | /* We need to carefully read the error status, ACK the errors, |
3 | * prevent recursive traps, and pass the information on to C |
4 | * code for logging. |
5 | * |
6 | * We pass the AFAR in as-is, and we encode the status |
7 | * information as described in asm-sparc64/sfafsr.h |
8 | */ |
9 | .type __spitfire_access_error,#function |
10 | __spitfire_access_error: |
11 | /* Disable ESTATE error reporting so that we do not take |
12 | * recursive traps and RED state the processor. |
13 | */ |
14 | stxa %g0, [%g0] ASI_ESTATE_ERROR_EN |
15 | membar #Sync |
16 | |
17 | mov UDBE_UE, %g1 |
18 | ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR |
19 | |
20 | /* __spitfire_cee_trap branches here with AFSR in %g4 and |
21 | * UDBE_CE in %g1. It only clears ESTATE_ERR_CE in the ESTATE |
22 | * Error Enable register. |
23 | */ |
24 | __spitfire_cee_trap_continue: |
25 | ldxa [%g0] ASI_AFAR, %g5 ! Get AFAR |
26 | |
27 | rdpr %tt, %g3 |
28 | and %g3, 0x1ff, %g3 ! Paranoia |
29 | sllx %g3, SFSTAT_TRAP_TYPE_SHIFT, %g3 |
30 | or %g4, %g3, %g4 |
31 | rdpr %tl, %g3 |
32 | cmp %g3, 1 |
33 | mov 1, %g3 |
34 | bleu %xcc, 1f |
35 | sllx %g3, SFSTAT_TL_GT_ONE_SHIFT, %g3 |
36 | |
37 | or %g4, %g3, %g4 |
38 | |
39 | /* Read in the UDB error register state, clearing the sticky |
40 | * error bits as-needed. We only clear them if the UE bit is |
41 | * set. Likewise, __spitfire_cee_trap below will only do so |
42 | * if the CE bit is set. |
43 | * |
44 | * NOTE: UltraSparc-I/II have high and low UDB error |
45 | * registers, corresponding to the two UDB units |
46 | * present on those chips. UltraSparc-IIi only |
47 | * has a single UDB, called "SDB" in the manual. |
48 | * For IIi the upper UDB register always reads |
49 | * as zero so for our purposes things will just |
50 | * work with the checks below. |
51 | */ |
52 | 1: ldxa [%g0] ASI_UDBH_ERROR_R, %g3 |
53 | and %g3, 0x3ff, %g7 ! Paranoia |
54 | sllx %g7, SFSTAT_UDBH_SHIFT, %g7 |
55 | or %g4, %g7, %g4 |
56 | andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE |
57 | be,pn %xcc, 1f |
58 | nop |
59 | stxa %g3, [%g0] ASI_UDB_ERROR_W |
60 | membar #Sync |
61 | |
62 | 1: mov 0x18, %g3 |
63 | ldxa [%g3] ASI_UDBL_ERROR_R, %g3 |
64 | and %g3, 0x3ff, %g7 ! Paranoia |
65 | sllx %g7, SFSTAT_UDBL_SHIFT, %g7 |
66 | or %g4, %g7, %g4 |
67 | andcc %g3, %g1, %g3 ! UDBE_UE or UDBE_CE |
68 | be,pn %xcc, 1f |
69 | nop |
70 | mov 0x18, %g7 |
71 | stxa %g3, [%g7] ASI_UDB_ERROR_W |
72 | membar #Sync |
73 | |
74 | 1: /* Ok, now that we've latched the error state, clear the |
75 | * sticky bits in the AFSR. |
76 | */ |
77 | stxa %g4, [%g0] ASI_AFSR |
78 | membar #Sync |
79 | |
80 | rdpr %tl, %g2 |
81 | cmp %g2, 1 |
82 | rdpr %pil, %g2 |
83 | bleu,pt %xcc, 1f |
84 | wrpr %g0, PIL_NORMAL_MAX, %pil |
85 | |
86 | ba,pt %xcc, etraptl1 |
87 | rd %pc, %g7 |
88 | |
89 | ba,a,pt %xcc, 2f |
90 | nop |
91 | |
92 | 1: ba,pt %xcc, etrap_irq |
93 | rd %pc, %g7 |
94 | |
95 | 2: |
96 | #ifdef CONFIG_TRACE_IRQFLAGS |
97 | call trace_hardirqs_off |
98 | nop |
99 | #endif |
100 | mov %l4, %o1 |
101 | mov %l5, %o2 |
102 | call spitfire_access_error |
103 | add %sp, PTREGS_OFF, %o0 |
104 | ba,a,pt %xcc, rtrap |
105 | .size __spitfire_access_error,.-__spitfire_access_error |
106 | |
107 | /* This is the trap handler entry point for ECC correctable |
108 | * errors. They are corrected, but we listen for the trap so |
109 | * that the event can be logged. |
110 | * |
111 | * Disrupting errors are either: |
112 | * 1) single-bit ECC errors during UDB reads to system |
113 | * memory |
114 | * 2) data parity errors during write-back events |
115 | * |
116 | * As far as I can make out from the manual, the CEE trap is |
117 | * only for correctable errors during memory read accesses by |
118 | * the front-end of the processor. |
119 | * |
120 | * The code below is only for trap level 1 CEE events, as it |
121 | * is the only situation where we can safely record and log. |
122 | * For trap level >1 we just clear the CE bit in the AFSR and |
123 | * return. |
124 | * |
125 | * This is just like __spiftire_access_error above, but it |
126 | * specifically handles correctable errors. If an |
127 | * uncorrectable error is indicated in the AFSR we will branch |
128 | * directly above to __spitfire_access_error to handle it |
129 | * instead. Uncorrectable therefore takes priority over |
130 | * correctable, and the error logging C code will notice this |
131 | * case by inspecting the trap type. |
132 | */ |
133 | .type __spitfire_cee_trap,#function |
134 | __spitfire_cee_trap: |
135 | ldxa [%g0] ASI_AFSR, %g4 ! Get AFSR |
136 | mov 1, %g3 |
137 | sllx %g3, SFAFSR_UE_SHIFT, %g3 |
138 | andcc %g4, %g3, %g0 ! Check for UE |
139 | bne,pn %xcc, __spitfire_access_error |
140 | nop |
141 | |
142 | /* Ok, in this case we only have a correctable error. |
143 | * Indicate we only wish to capture that state in register |
144 | * %g1, and we only disable CE error reporting unlike UE |
145 | * handling which disables all errors. |
146 | */ |
147 | ldxa [%g0] ASI_ESTATE_ERROR_EN, %g3 |
148 | andn %g3, ESTATE_ERR_CE, %g3 |
149 | stxa %g3, [%g0] ASI_ESTATE_ERROR_EN |
150 | membar #Sync |
151 | |
152 | /* Preserve AFSR in %g4, indicate UDB state to capture in %g1 */ |
153 | ba,pt %xcc, __spitfire_cee_trap_continue |
154 | mov UDBE_CE, %g1 |
155 | .size __spitfire_cee_trap,.-__spitfire_cee_trap |
156 | |
157 | .type __spitfire_data_access_exception_tl1,#function |
158 | __spitfire_data_access_exception_tl1: |
159 | rdpr %pstate, %g4 |
160 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
161 | mov TLB_SFSR, %g3 |
162 | mov DMMU_SFAR, %g5 |
163 | ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR |
164 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR |
165 | stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit |
166 | membar #Sync |
167 | rdpr %tt, %g3 |
168 | cmp %g3, 0x80 ! first win spill/fill trap |
169 | blu,pn %xcc, 1f |
170 | cmp %g3, 0xff ! last win spill/fill trap |
171 | bgu,pn %xcc, 1f |
172 | nop |
173 | ba,pt %xcc, winfix_dax |
174 | rdpr %tpc, %g3 |
175 | 1: sethi %hi(109f), %g7 |
176 | ba,pt %xcc, etraptl1 |
177 | 109: or %g7, %lo(109b), %g7 |
178 | mov %l4, %o1 |
179 | mov %l5, %o2 |
180 | call spitfire_data_access_exception_tl1 |
181 | add %sp, PTREGS_OFF, %o0 |
182 | ba,a,pt %xcc, rtrap |
183 | .size __spitfire_data_access_exception_tl1,.-__spitfire_data_access_exception_tl1 |
184 | |
185 | .type __spitfire_data_access_exception,#function |
186 | __spitfire_data_access_exception: |
187 | rdpr %pstate, %g4 |
188 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
189 | mov TLB_SFSR, %g3 |
190 | mov DMMU_SFAR, %g5 |
191 | ldxa [%g3] ASI_DMMU, %g4 ! Get SFSR |
192 | ldxa [%g5] ASI_DMMU, %g5 ! Get SFAR |
193 | stxa %g0, [%g3] ASI_DMMU ! Clear SFSR.FaultValid bit |
194 | membar #Sync |
195 | sethi %hi(109f), %g7 |
196 | ba,pt %xcc, etrap |
197 | 109: or %g7, %lo(109b), %g7 |
198 | mov %l4, %o1 |
199 | mov %l5, %o2 |
200 | call spitfire_data_access_exception |
201 | add %sp, PTREGS_OFF, %o0 |
202 | ba,a,pt %xcc, rtrap |
203 | .size __spitfire_data_access_exception,.-__spitfire_data_access_exception |
204 | |
205 | .type __spitfire_insn_access_exception_tl1,#function |
206 | __spitfire_insn_access_exception_tl1: |
207 | rdpr %pstate, %g4 |
208 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
209 | mov TLB_SFSR, %g3 |
210 | ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR |
211 | rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC |
212 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit |
213 | membar #Sync |
214 | sethi %hi(109f), %g7 |
215 | ba,pt %xcc, etraptl1 |
216 | 109: or %g7, %lo(109b), %g7 |
217 | mov %l4, %o1 |
218 | mov %l5, %o2 |
219 | call spitfire_insn_access_exception_tl1 |
220 | add %sp, PTREGS_OFF, %o0 |
221 | ba,a,pt %xcc, rtrap |
222 | .size __spitfire_insn_access_exception_tl1,.-__spitfire_insn_access_exception_tl1 |
223 | |
224 | .type __spitfire_insn_access_exception,#function |
225 | __spitfire_insn_access_exception: |
226 | rdpr %pstate, %g4 |
227 | wrpr %g4, PSTATE_MG|PSTATE_AG, %pstate |
228 | mov TLB_SFSR, %g3 |
229 | ldxa [%g3] ASI_IMMU, %g4 ! Get SFSR |
230 | rdpr %tpc, %g5 ! IMMU has no SFAR, use TPC |
231 | stxa %g0, [%g3] ASI_IMMU ! Clear FaultValid bit |
232 | membar #Sync |
233 | sethi %hi(109f), %g7 |
234 | ba,pt %xcc, etrap |
235 | 109: or %g7, %lo(109b), %g7 |
236 | mov %l4, %o1 |
237 | mov %l5, %o2 |
238 | call spitfire_insn_access_exception |
239 | add %sp, PTREGS_OFF, %o0 |
240 | ba,a,pt %xcc, rtrap |
241 | .size __spitfire_insn_access_exception,.-__spitfire_insn_access_exception |
242 | |