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 /* Preserve rejected frames without trusting their internal offsets. */ 48 void 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 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 * 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 * 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 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 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 * 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 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 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 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 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 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