1 // SPDX-License-Identifier: GPL-2.0
2 /*
3 * linux/arch/alpha/kernel/err_common.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
18 #include "err_impl.h"
19 #include "proto.h"
20
21 /*
22 * err_print_prefix -- error handling print routines should prefix
23 * all prints with this
24 */
25 char *err_print_prefix = KERN_NOTICE;
26
27
28 /*
29 * Generic
30 */
31 void
mchk_dump_mem(void * data,size_t length,char ** annotation)32 mchk_dump_mem(void *data, size_t length, char **annotation)
33 {
34 unsigned long *ldata = data;
35 size_t i;
36
37 for (i = 0; (i * sizeof(*ldata)) < length; i++) {
38 if (annotation && !annotation[i])
39 annotation = NULL;
40 printk("%s %08x: %016lx %s\n",
41 err_print_prefix,
42 (unsigned)(i * sizeof(*ldata)), ldata[i],
43 annotation ? annotation[i] : "");
44 }
45 }
46
47 /* Preserve rejected frames without trusting their internal offsets. */
48 void
mchk_dump_logout_frame_raw(struct el_common * header)49 mchk_dump_logout_frame_raw(struct el_common *header)
50 {
51 size_t length = header->size;
52
53 /* Bound diagnostic output and never read a partial final quadword. */
54 if (length > 1024)
55 length = 1024;
56 length &= ~7UL;
57 mchk_dump_mem(header, length, NULL);
58 }
59
60 void
mchk_dump_logout_frame(struct el_common * mchk_header)61 mchk_dump_logout_frame(struct el_common *mchk_header)
62 {
63 printk("%s -- Frame Header --\n"
64 " Frame Size: %d (0x%x) bytes\n"
65 " Flags: %s%s\n"
66 " MCHK Code: 0x%x\n"
67 " Frame Rev: %d\n"
68 " Proc Offset: 0x%08x\n"
69 " Sys Offset: 0x%08x\n"
70 " -- Processor Region --\n",
71 err_print_prefix,
72 mchk_header->size, mchk_header->size,
73 mchk_header->retry ? "RETRY " : "",
74 mchk_header->err2 ? "SECOND_ERR " : "",
75 mchk_header->code,
76 mchk_header->frame_rev,
77 mchk_header->proc_offset,
78 mchk_header->sys_offset);
79
80 mchk_dump_mem((void *)
81 ((unsigned long)mchk_header + mchk_header->proc_offset),
82 mchk_header->sys_offset - mchk_header->proc_offset,
83 NULL);
84
85 printk("%s -- System Region --\n", err_print_prefix);
86 mchk_dump_mem((void *)
87 ((unsigned long)mchk_header + mchk_header->sys_offset),
88 mchk_header->size - mchk_header->sys_offset,
89 NULL);
90 printk("%s -- End of Frame --\n", err_print_prefix);
91 }
92
93
94 /*
95 * Console Data Log
96 */
97 /* Data */
98 static struct el_subpacket_handler *subpacket_handler_list = NULL;
99 static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
100
101 static struct el_subpacket *
el_process_header_subpacket(struct el_subpacket * header)102 el_process_header_subpacket(struct el_subpacket *header)
103 {
104 union el_timestamp timestamp;
105 char *name = "UNKNOWN EVENT";
106 int packet_count = 0;
107 int length = 0;
108
109 if (header->class != EL_CLASS__HEADER) {
110 printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
111 err_print_prefix,
112 header->class, header->type);
113 return NULL;
114 }
115
116 switch(header->type) {
117 case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
118 name = "SYSTEM ERROR";
119 length = header->by_type.sys_err.frame_length;
120 packet_count =
121 header->by_type.sys_err.frame_packet_count;
122 timestamp.as_int = 0;
123 break;
124 case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
125 name = "SYSTEM EVENT";
126 length = header->by_type.sys_event.frame_length;
127 packet_count =
128 header->by_type.sys_event.frame_packet_count;
129 timestamp = header->by_type.sys_event.timestamp;
130 break;
131 case EL_TYPE__HEADER__HALT_FRAME:
132 name = "ERROR HALT";
133 length = header->by_type.err_halt.frame_length;
134 packet_count =
135 header->by_type.err_halt.frame_packet_count;
136 timestamp = header->by_type.err_halt.timestamp;
137 break;
138 case EL_TYPE__HEADER__LOGOUT_FRAME:
139 name = "LOGOUT FRAME";
140 length = header->by_type.logout_header.frame_length;
141 packet_count = 1;
142 timestamp.as_int = 0;
143 break;
144 default: /* Unknown */
145 printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
146 err_print_prefix,
147 header->class, header->type);
148 return NULL;
149 }
150
151 printk("%s*** %s:\n"
152 " CLASS %d, TYPE %d\n",
153 err_print_prefix,
154 name,
155 header->class, header->type);
156 el_print_timestamp(×tamp);
157
158 /*
159 * Process the subpackets
160 */
161 el_process_subpackets(header, packet_count);
162
163 /* return the next header */
164 header = (struct el_subpacket *)
165 ((unsigned long)header + header->length + length);
166 return header;
167 }
168
169 static struct el_subpacket *
el_process_subpacket_reg(struct el_subpacket * header)170 el_process_subpacket_reg(struct el_subpacket *header)
171 {
172 struct el_subpacket *next = NULL;
173 struct el_subpacket_handler *h = subpacket_handler_list;
174
175 for (; h && h->class != header->class; h = h->next);
176 if (h) next = h->handler(header);
177
178 return next;
179 }
180
181 void
el_print_timestamp(union el_timestamp * timestamp)182 el_print_timestamp(union el_timestamp *timestamp)
183 {
184 if (timestamp->as_int)
185 printk("%s TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n",
186 err_print_prefix,
187 timestamp->b.month, timestamp->b.day,
188 timestamp->b.year, timestamp->b.hour,
189 timestamp->b.minute, timestamp->b.second);
190 }
191
192 void
el_process_subpackets(struct el_subpacket * header,int packet_count)193 el_process_subpackets(struct el_subpacket *header, int packet_count)
194 {
195 struct el_subpacket *subpacket;
196 int i;
197
198 subpacket = (struct el_subpacket *)
199 ((unsigned long)header + header->length);
200
201 for (i = 0; subpacket && i < packet_count; i++) {
202 printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
203 subpacket = el_process_subpacket(subpacket);
204 }
205 }
206
207 struct el_subpacket *
el_process_subpacket(struct el_subpacket * header)208 el_process_subpacket(struct el_subpacket *header)
209 {
210 struct el_subpacket *next = NULL;
211
212 switch(header->class) {
213 case EL_CLASS__TERMINATION:
214 /* Termination packet, there are no more */
215 break;
216 case EL_CLASS__HEADER:
217 next = el_process_header_subpacket(header);
218 break;
219 default:
220 if (NULL == (next = el_process_subpacket_reg(header))) {
221 printk("%s** Unexpected header CLASS %d TYPE %d"
222 " -- aborting.\n",
223 err_print_prefix,
224 header->class, header->type);
225 }
226 break;
227 }
228
229 return next;
230 }
231
232 void
el_annotate_subpacket(struct el_subpacket * header)233 el_annotate_subpacket(struct el_subpacket *header)
234 {
235 struct el_subpacket_annotation *a;
236 char **annotation = NULL;
237
238 for (a = subpacket_annotation_list; a; a = a->next) {
239 if (a->class == header->class &&
240 a->type == header->type &&
241 a->revision == header->revision) {
242 /*
243 * We found the annotation
244 */
245 annotation = a->annotation;
246 printk("%s %s\n", err_print_prefix, a->description);
247 break;
248 }
249 }
250
251 mchk_dump_mem(header, header->length, annotation);
252 }
253
254 static void __init
cdl_process_console_data_log(int cpu,struct percpu_struct * pcpu)255 cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
256 {
257 struct el_subpacket *header = (struct el_subpacket *)
258 (IDENT_ADDR | pcpu->console_data_log_pa);
259 int err;
260
261 printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
262 "*** Error(s) were logged on a previous boot\n",
263 err_print_prefix, cpu);
264
265 for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
266 header = el_process_subpacket(header);
267
268 /* let the console know it's ok to clear the error(s) at restart */
269 pcpu->console_data_log_pa = 0;
270
271 printk("%s*** %d total error(s) logged\n"
272 "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n",
273 err_print_prefix, err, cpu);
274 }
275
276 void __init
cdl_check_console_data_log(void)277 cdl_check_console_data_log(void)
278 {
279 struct percpu_struct *pcpu;
280 unsigned long cpu;
281
282 for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
283 pcpu = (struct percpu_struct *)
284 ((unsigned long)hwrpb + hwrpb->processor_offset
285 + cpu * hwrpb->processor_size);
286 if (pcpu->console_data_log_pa)
287 cdl_process_console_data_log(cpu, pcpu);
288 }
289
290 }
291
292 int __init
cdl_register_subpacket_annotation(struct el_subpacket_annotation * new)293 cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
294 {
295 struct el_subpacket_annotation *a = subpacket_annotation_list;
296
297 if (a == NULL) subpacket_annotation_list = new;
298 else {
299 for (; a->next != NULL; a = a->next) {
300 if ((a->class == new->class && a->type == new->type) ||
301 a == new) {
302 printk("Attempted to re-register "
303 "subpacket annotation\n");
304 return -EINVAL;
305 }
306 }
307 a->next = new;
308 }
309 new->next = NULL;
310
311 return 0;
312 }
313
314 int __init
cdl_register_subpacket_handler(struct el_subpacket_handler * new)315 cdl_register_subpacket_handler(struct el_subpacket_handler *new)
316 {
317 struct el_subpacket_handler *h = subpacket_handler_list;
318
319 if (h == NULL) subpacket_handler_list = new;
320 else {
321 for (; h->next != NULL; h = h->next) {
322 if (h->class == new->class || h == new) {
323 printk("Attempted to re-register "
324 "subpacket handler\n");
325 return -EINVAL;
326 }
327 }
328 h->next = new;
329 }
330 new->next = NULL;
331
332 return 0;
333 }
334
335