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 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 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 * 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(×tamp); 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 * 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 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 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 * 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 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 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 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 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 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