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