1 | // SPDX-License-Identifier: GPL-2.0 |
2 | /* |
3 | * linux/arch/alpha/kernel/err_ev7.c |
4 | * |
5 | * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation) |
6 | * |
7 | * Error handling code supporting Alpha systems |
8 | */ |
9 | |
10 | #include <linux/init.h> |
11 | #include <linux/sched.h> |
12 | |
13 | #include <asm/io.h> |
14 | #include <asm/hwrpb.h> |
15 | #include <asm/smp.h> |
16 | #include <asm/err_common.h> |
17 | #include <asm/err_ev7.h> |
18 | |
19 | #include "err_impl.h" |
20 | #include "proto.h" |
21 | |
22 | struct ev7_lf_subpackets * |
23 | ev7_collect_logout_frame_subpackets(struct el_subpacket *el_ptr, |
24 | struct ev7_lf_subpackets *lf_subpackets) |
25 | { |
26 | struct el_subpacket *subpacket; |
27 | int i; |
28 | |
29 | /* |
30 | * A Marvel machine check frame is always packaged in an |
31 | * el_subpacket of class HEADER, type LOGOUT_FRAME. |
32 | */ |
33 | if (el_ptr->class != EL_CLASS__HEADER || |
34 | el_ptr->type != EL_TYPE__HEADER__LOGOUT_FRAME) |
35 | return NULL; |
36 | |
37 | /* |
38 | * It is a logout frame header. Look at the one subpacket. |
39 | */ |
40 | el_ptr = (struct el_subpacket *) |
41 | ((unsigned long)el_ptr + el_ptr->length); |
42 | |
43 | /* |
44 | * It has to be class PAL, type LOGOUT_FRAME. |
45 | */ |
46 | if (el_ptr->class != EL_CLASS__PAL || |
47 | el_ptr->type != EL_TYPE__PAL__LOGOUT_FRAME) |
48 | return NULL; |
49 | |
50 | lf_subpackets->logout = (struct ev7_pal_logout_subpacket *) |
51 | el_ptr->by_type.raw.data_start; |
52 | |
53 | /* |
54 | * Process the subpackets. |
55 | */ |
56 | subpacket = (struct el_subpacket *) |
57 | ((unsigned long)el_ptr + el_ptr->length); |
58 | for (i = 0; |
59 | subpacket && i < lf_subpackets->logout->subpacket_count; |
60 | subpacket = (struct el_subpacket *) |
61 | ((unsigned long)subpacket + subpacket->length), i++) { |
62 | /* |
63 | * All subpackets should be class PAL. |
64 | */ |
65 | if (subpacket->class != EL_CLASS__PAL) { |
66 | printk("%s**UNEXPECTED SUBPACKET CLASS %d " |
67 | "IN LOGOUT FRAME (packet %d\n" , |
68 | err_print_prefix, subpacket->class, i); |
69 | return NULL; |
70 | } |
71 | |
72 | /* |
73 | * Remember the subpacket. |
74 | */ |
75 | switch(subpacket->type) { |
76 | case EL_TYPE__PAL__EV7_PROCESSOR: |
77 | lf_subpackets->ev7 = |
78 | (struct ev7_pal_processor_subpacket *) |
79 | subpacket->by_type.raw.data_start; |
80 | break; |
81 | |
82 | case EL_TYPE__PAL__EV7_RBOX: |
83 | lf_subpackets->rbox = (struct ev7_pal_rbox_subpacket *) |
84 | subpacket->by_type.raw.data_start; |
85 | break; |
86 | |
87 | case EL_TYPE__PAL__EV7_ZBOX: |
88 | lf_subpackets->zbox = (struct ev7_pal_zbox_subpacket *) |
89 | subpacket->by_type.raw.data_start; |
90 | break; |
91 | |
92 | case EL_TYPE__PAL__EV7_IO: |
93 | lf_subpackets->io = (struct ev7_pal_io_subpacket *) |
94 | subpacket->by_type.raw.data_start; |
95 | break; |
96 | |
97 | case EL_TYPE__PAL__ENV__AMBIENT_TEMPERATURE: |
98 | case EL_TYPE__PAL__ENV__AIRMOVER_FAN: |
99 | case EL_TYPE__PAL__ENV__VOLTAGE: |
100 | case EL_TYPE__PAL__ENV__INTRUSION: |
101 | case EL_TYPE__PAL__ENV__POWER_SUPPLY: |
102 | case EL_TYPE__PAL__ENV__LAN: |
103 | case EL_TYPE__PAL__ENV__HOT_PLUG: |
104 | lf_subpackets->env[ev7_lf_env_index(subpacket->type)] = |
105 | (struct ev7_pal_environmental_subpacket *) |
106 | subpacket->by_type.raw.data_start; |
107 | break; |
108 | |
109 | default: |
110 | /* |
111 | * Don't know what kind of frame this is. |
112 | */ |
113 | return NULL; |
114 | } |
115 | } |
116 | |
117 | return lf_subpackets; |
118 | } |
119 | |
120 | void |
121 | ev7_machine_check(unsigned long vector, unsigned long la_ptr) |
122 | { |
123 | struct el_subpacket *el_ptr = (struct el_subpacket *)la_ptr; |
124 | char *saved_err_prefix = err_print_prefix; |
125 | |
126 | /* |
127 | * Sync the processor |
128 | */ |
129 | mb(); |
130 | draina(); |
131 | |
132 | err_print_prefix = KERN_CRIT; |
133 | printk("%s*CPU %s Error (Vector 0x%x) reported on CPU %d\n" , |
134 | err_print_prefix, |
135 | (vector == SCB_Q_PROCERR) ? "Correctable" : "Uncorrectable" , |
136 | (unsigned int)vector, (int)smp_processor_id()); |
137 | el_process_subpacket(el_ptr); |
138 | err_print_prefix = saved_err_prefix; |
139 | |
140 | /* |
141 | * Release the logout frame |
142 | */ |
143 | wrmces(mces: 0x7); |
144 | mb(); |
145 | } |
146 | |
147 | static char *el_ev7_processor_subpacket_annotation[] = { |
148 | "Subpacket Header" , "I_STAT" , "DC_STAT" , |
149 | "C_ADDR" , "C_SYNDROME_1" , "C_SYNDROME_0" , |
150 | "C_STAT" , "C_STS" , "MM_STAT" , |
151 | "EXC_ADDR" , "IER_CM" , "ISUM" , |
152 | "PAL_BASE" , "I_CTL" , "PROCESS_CONTEXT" , |
153 | "CBOX_CTL" , "CBOX_STP_CTL" , "CBOX_ACC_CTL" , |
154 | "CBOX_LCL_SET" , "CBOX_GLB_SET" , "BBOX_CTL" , |
155 | "BBOX_ERR_STS" , "BBOX_ERR_IDX" , "CBOX_DDP_ERR_STS" , |
156 | "BBOX_DAT_RMP" , NULL |
157 | }; |
158 | |
159 | static char *el_ev7_zbox_subpacket_annotation[] = { |
160 | "Subpacket Header" , |
161 | "ZBOX(0): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1" , |
162 | "ZBOX(0): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3" , |
163 | "ZBOX(0): DIFT_TIMEOUT / DRAM_ERR_ADR" , |
164 | "ZBOX(0): FRC_ERR_ADR / DRAM_MAPPER_CTL" , |
165 | "ZBOX(0): reserved / DIFT_ERR_STATUS" , |
166 | "ZBOX(1): DRAM_ERR_STATUS_2 / DRAM_ERR_STATUS_1" , |
167 | "ZBOX(1): DRAM_ERROR_CTL / DRAM_ERR_STATUS_3" , |
168 | "ZBOX(1): DIFT_TIMEOUT / DRAM_ERR_ADR" , |
169 | "ZBOX(1): FRC_ERR_ADR / DRAM_MAPPER_CTL" , |
170 | "ZBOX(1): reserved / DIFT_ERR_STATUS" , |
171 | "CBOX_CTL" , "CBOX_STP_CTL" , |
172 | "ZBOX(0)_ERROR_PA" , "ZBOX(1)_ERROR_PA" , |
173 | "ZBOX(0)_ORED_SYNDROME" ,"ZBOX(1)_ORED_SYNDROME" , |
174 | NULL |
175 | }; |
176 | |
177 | static char *el_ev7_rbox_subpacket_annotation[] = { |
178 | "Subpacket Header" , "RBOX_CFG" , "RBOX_N_CFG" , |
179 | "RBOX_S_CFG" , "RBOX_E_CFG" , "RBOX_W_CFG" , |
180 | "RBOX_N_ERR" , "RBOX_S_ERR" , "RBOX_E_ERR" , |
181 | "RBOX_W_ERR" , "RBOX_IO_CFG" , "RBOX_IO_ERR" , |
182 | "RBOX_L_ERR" , "RBOX_WHOAMI" , "RBOX_IMASL" , |
183 | "RBOX_INTQ" , "RBOX_INT" , NULL |
184 | }; |
185 | |
186 | static char *el_ev7_io_subpacket_annotation[] = { |
187 | "Subpacket Header" , "IO_ASIC_REV" , "IO_SYS_REV" , |
188 | "IO7_UPH" , "HPI_CTL" , "CRD_CTL" , |
189 | "HEI_CTL" , "PO7_ERROR_SUM" ,"PO7_UNCRR_SYM" , |
190 | "PO7_CRRCT_SYM" , "PO7_UGBGE_SYM" ,"PO7_ERR_PKT0" , |
191 | "PO7_ERR_PKT1" , "reserved" , "reserved" , |
192 | "PO0_ERR_SUM" , "PO0_TLB_ERR" , "PO0_SPL_COMPLT" , |
193 | "PO0_TRANS_SUM" , "PO0_FIRST_ERR" ,"PO0_MULT_ERR" , |
194 | "DM CSR PH" , "DM CSR PH" , "DM CSR PH" , |
195 | "DM CSR PH" , "reserved" , |
196 | "PO1_ERR_SUM" , "PO1_TLB_ERR" , "PO1_SPL_COMPLT" , |
197 | "PO1_TRANS_SUM" , "PO1_FIRST_ERR" ,"PO1_MULT_ERR" , |
198 | "DM CSR PH" , "DM CSR PH" , "DM CSR PH" , |
199 | "DM CSR PH" , "reserved" , |
200 | "PO2_ERR_SUM" , "PO2_TLB_ERR" , "PO2_SPL_COMPLT" , |
201 | "PO2_TRANS_SUM" , "PO2_FIRST_ERR" ,"PO2_MULT_ERR" , |
202 | "DM CSR PH" , "DM CSR PH" , "DM CSR PH" , |
203 | "DM CSR PH" , "reserved" , |
204 | "PO3_ERR_SUM" , "PO3_TLB_ERR" , "PO3_SPL_COMPLT" , |
205 | "PO3_TRANS_SUM" , "PO3_FIRST_ERR" ,"PO3_MULT_ERR" , |
206 | "DM CSR PH" , "DM CSR PH" , "DM CSR PH" , |
207 | "DM CSR PH" , "reserved" , |
208 | NULL |
209 | }; |
210 | |
211 | static struct el_subpacket_annotation el_ev7_pal_annotations[] = { |
212 | SUBPACKET_ANNOTATION(EL_CLASS__PAL, |
213 | EL_TYPE__PAL__EV7_PROCESSOR, |
214 | 1, |
215 | "EV7 Processor Subpacket" , |
216 | el_ev7_processor_subpacket_annotation), |
217 | SUBPACKET_ANNOTATION(EL_CLASS__PAL, |
218 | EL_TYPE__PAL__EV7_ZBOX, |
219 | 1, |
220 | "EV7 ZBOX Subpacket" , |
221 | el_ev7_zbox_subpacket_annotation), |
222 | SUBPACKET_ANNOTATION(EL_CLASS__PAL, |
223 | EL_TYPE__PAL__EV7_RBOX, |
224 | 1, |
225 | "EV7 RBOX Subpacket" , |
226 | el_ev7_rbox_subpacket_annotation), |
227 | SUBPACKET_ANNOTATION(EL_CLASS__PAL, |
228 | EL_TYPE__PAL__EV7_IO, |
229 | 1, |
230 | "EV7 IO Subpacket" , |
231 | el_ev7_io_subpacket_annotation) |
232 | }; |
233 | |
234 | static struct el_subpacket * |
235 | ev7_process_pal_subpacket(struct el_subpacket *) |
236 | { |
237 | struct ev7_pal_subpacket *packet; |
238 | |
239 | if (header->class != EL_CLASS__PAL) { |
240 | printk("%s ** Unexpected header CLASS %d TYPE %d, aborting\n" , |
241 | err_print_prefix, |
242 | header->class, header->type); |
243 | return NULL; |
244 | } |
245 | |
246 | packet = (struct ev7_pal_subpacket *)header->by_type.raw.data_start; |
247 | |
248 | switch(header->type) { |
249 | case EL_TYPE__PAL__LOGOUT_FRAME: |
250 | printk("%s*** MCHK occurred on LPID %lld (RBOX %llx)\n" , |
251 | err_print_prefix, |
252 | packet->by_type.logout.whami, |
253 | packet->by_type.logout.rbox_whami); |
254 | el_print_timestamp(&packet->by_type.logout.timestamp); |
255 | printk("%s EXC_ADDR: %016llx\n" |
256 | " HALT_CODE: %llx\n" , |
257 | err_print_prefix, |
258 | packet->by_type.logout.exc_addr, |
259 | packet->by_type.logout.halt_code); |
260 | el_process_subpackets(header, |
261 | packet->by_type.logout.subpacket_count); |
262 | break; |
263 | default: |
264 | printk("%s ** PAL TYPE %d SUBPACKET\n" , |
265 | err_print_prefix, |
266 | header->type); |
267 | el_annotate_subpacket(header); |
268 | break; |
269 | } |
270 | |
271 | return (struct el_subpacket *)((unsigned long)header + header->length); |
272 | } |
273 | |
274 | struct el_subpacket_handler ev7_pal_subpacket_handler = |
275 | SUBPACKET_HANDLER_INIT(EL_CLASS__PAL, ev7_process_pal_subpacket); |
276 | |
277 | void __init |
278 | ev7_register_error_handlers(void) |
279 | { |
280 | int i; |
281 | |
282 | for (i = 0; i < ARRAY_SIZE(el_ev7_pal_annotations); i++) |
283 | cdl_register_subpacket_annotation(&el_ev7_pal_annotations[i]); |
284 | |
285 | cdl_register_subpacket_handler(&ev7_pal_subpacket_handler); |
286 | } |
287 | |
288 | |