xref: /linux/arch/alpha/kernel/err_common.c (revision 742f62b63904cdc20a364a49d2861e32464a0af7)
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(&timestamp);
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