1*b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
21da177e4SLinus Torvalds /*
31da177e4SLinus Torvalds * linux/arch/alpha/kernel/err_common.c
41da177e4SLinus Torvalds *
51da177e4SLinus Torvalds * Copyright (C) 2000 Jeff Wiedemeier (Compaq Computer Corporation)
61da177e4SLinus Torvalds *
71da177e4SLinus Torvalds * Error handling code supporting Alpha systems
81da177e4SLinus Torvalds */
91da177e4SLinus Torvalds
101da177e4SLinus Torvalds #include <linux/init.h>
111da177e4SLinus Torvalds #include <linux/sched.h>
121da177e4SLinus Torvalds
131da177e4SLinus Torvalds #include <asm/io.h>
141da177e4SLinus Torvalds #include <asm/hwrpb.h>
151da177e4SLinus Torvalds #include <asm/smp.h>
161da177e4SLinus Torvalds #include <asm/err_common.h>
171da177e4SLinus Torvalds
181da177e4SLinus Torvalds #include "err_impl.h"
191da177e4SLinus Torvalds #include "proto.h"
201da177e4SLinus Torvalds
211da177e4SLinus Torvalds /*
221da177e4SLinus Torvalds * err_print_prefix -- error handling print routines should prefix
231da177e4SLinus Torvalds * all prints with this
241da177e4SLinus Torvalds */
251da177e4SLinus Torvalds char *err_print_prefix = KERN_NOTICE;
261da177e4SLinus Torvalds
271da177e4SLinus Torvalds
281da177e4SLinus Torvalds /*
291da177e4SLinus Torvalds * Generic
301da177e4SLinus Torvalds */
311da177e4SLinus Torvalds void
mchk_dump_mem(void * data,size_t length,char ** annotation)321da177e4SLinus Torvalds mchk_dump_mem(void *data, size_t length, char **annotation)
331da177e4SLinus Torvalds {
341da177e4SLinus Torvalds unsigned long *ldata = data;
351da177e4SLinus Torvalds size_t i;
361da177e4SLinus Torvalds
371da177e4SLinus Torvalds for (i = 0; (i * sizeof(*ldata)) < length; i++) {
381da177e4SLinus Torvalds if (annotation && !annotation[i])
391da177e4SLinus Torvalds annotation = NULL;
401da177e4SLinus Torvalds printk("%s %08x: %016lx %s\n",
411da177e4SLinus Torvalds err_print_prefix,
421da177e4SLinus Torvalds (unsigned)(i * sizeof(*ldata)), ldata[i],
431da177e4SLinus Torvalds annotation ? annotation[i] : "");
441da177e4SLinus Torvalds }
451da177e4SLinus Torvalds }
461da177e4SLinus Torvalds
471da177e4SLinus Torvalds void
mchk_dump_logout_frame(struct el_common * mchk_header)481da177e4SLinus Torvalds mchk_dump_logout_frame(struct el_common *mchk_header)
491da177e4SLinus Torvalds {
501da177e4SLinus Torvalds printk("%s -- Frame Header --\n"
511da177e4SLinus Torvalds " Frame Size: %d (0x%x) bytes\n"
521da177e4SLinus Torvalds " Flags: %s%s\n"
531da177e4SLinus Torvalds " MCHK Code: 0x%x\n"
541da177e4SLinus Torvalds " Frame Rev: %d\n"
551da177e4SLinus Torvalds " Proc Offset: 0x%08x\n"
561da177e4SLinus Torvalds " Sys Offset: 0x%08x\n"
571da177e4SLinus Torvalds " -- Processor Region --\n",
581da177e4SLinus Torvalds err_print_prefix,
591da177e4SLinus Torvalds mchk_header->size, mchk_header->size,
601da177e4SLinus Torvalds mchk_header->retry ? "RETRY " : "",
611da177e4SLinus Torvalds mchk_header->err2 ? "SECOND_ERR " : "",
621da177e4SLinus Torvalds mchk_header->code,
631da177e4SLinus Torvalds mchk_header->frame_rev,
641da177e4SLinus Torvalds mchk_header->proc_offset,
651da177e4SLinus Torvalds mchk_header->sys_offset);
661da177e4SLinus Torvalds
671da177e4SLinus Torvalds mchk_dump_mem((void *)
681da177e4SLinus Torvalds ((unsigned long)mchk_header + mchk_header->proc_offset),
691da177e4SLinus Torvalds mchk_header->sys_offset - mchk_header->proc_offset,
701da177e4SLinus Torvalds NULL);
711da177e4SLinus Torvalds
721da177e4SLinus Torvalds printk("%s -- System Region --\n", err_print_prefix);
731da177e4SLinus Torvalds mchk_dump_mem((void *)
741da177e4SLinus Torvalds ((unsigned long)mchk_header + mchk_header->sys_offset),
751da177e4SLinus Torvalds mchk_header->size - mchk_header->sys_offset,
761da177e4SLinus Torvalds NULL);
771da177e4SLinus Torvalds printk("%s -- End of Frame --\n", err_print_prefix);
781da177e4SLinus Torvalds }
791da177e4SLinus Torvalds
801da177e4SLinus Torvalds
811da177e4SLinus Torvalds /*
821da177e4SLinus Torvalds * Console Data Log
831da177e4SLinus Torvalds */
841da177e4SLinus Torvalds /* Data */
851da177e4SLinus Torvalds static struct el_subpacket_handler *subpacket_handler_list = NULL;
861da177e4SLinus Torvalds static struct el_subpacket_annotation *subpacket_annotation_list = NULL;
871da177e4SLinus Torvalds
881da177e4SLinus Torvalds static struct el_subpacket *
el_process_header_subpacket(struct el_subpacket * header)891da177e4SLinus Torvalds el_process_header_subpacket(struct el_subpacket *header)
901da177e4SLinus Torvalds {
911da177e4SLinus Torvalds union el_timestamp timestamp;
921da177e4SLinus Torvalds char *name = "UNKNOWN EVENT";
931da177e4SLinus Torvalds int packet_count = 0;
941da177e4SLinus Torvalds int length = 0;
951da177e4SLinus Torvalds
961da177e4SLinus Torvalds if (header->class != EL_CLASS__HEADER) {
971da177e4SLinus Torvalds printk("%s** Unexpected header CLASS %d TYPE %d, aborting\n",
981da177e4SLinus Torvalds err_print_prefix,
991da177e4SLinus Torvalds header->class, header->type);
1001da177e4SLinus Torvalds return NULL;
1011da177e4SLinus Torvalds }
1021da177e4SLinus Torvalds
1031da177e4SLinus Torvalds switch(header->type) {
1041da177e4SLinus Torvalds case EL_TYPE__HEADER__SYSTEM_ERROR_FRAME:
1051da177e4SLinus Torvalds name = "SYSTEM ERROR";
1061da177e4SLinus Torvalds length = header->by_type.sys_err.frame_length;
1071da177e4SLinus Torvalds packet_count =
1081da177e4SLinus Torvalds header->by_type.sys_err.frame_packet_count;
1091da177e4SLinus Torvalds timestamp.as_int = 0;
1101da177e4SLinus Torvalds break;
1111da177e4SLinus Torvalds case EL_TYPE__HEADER__SYSTEM_EVENT_FRAME:
1121da177e4SLinus Torvalds name = "SYSTEM EVENT";
1131da177e4SLinus Torvalds length = header->by_type.sys_event.frame_length;
1141da177e4SLinus Torvalds packet_count =
1151da177e4SLinus Torvalds header->by_type.sys_event.frame_packet_count;
1161da177e4SLinus Torvalds timestamp = header->by_type.sys_event.timestamp;
1171da177e4SLinus Torvalds break;
1181da177e4SLinus Torvalds case EL_TYPE__HEADER__HALT_FRAME:
1191da177e4SLinus Torvalds name = "ERROR HALT";
1201da177e4SLinus Torvalds length = header->by_type.err_halt.frame_length;
1211da177e4SLinus Torvalds packet_count =
1221da177e4SLinus Torvalds header->by_type.err_halt.frame_packet_count;
1231da177e4SLinus Torvalds timestamp = header->by_type.err_halt.timestamp;
1241da177e4SLinus Torvalds break;
1251da177e4SLinus Torvalds case EL_TYPE__HEADER__LOGOUT_FRAME:
1261da177e4SLinus Torvalds name = "LOGOUT FRAME";
1271da177e4SLinus Torvalds length = header->by_type.logout_header.frame_length;
1281da177e4SLinus Torvalds packet_count = 1;
1291da177e4SLinus Torvalds timestamp.as_int = 0;
1301da177e4SLinus Torvalds break;
1311da177e4SLinus Torvalds default: /* Unknown */
1321da177e4SLinus Torvalds printk("%s** Unknown header - CLASS %d TYPE %d, aborting\n",
1331da177e4SLinus Torvalds err_print_prefix,
1341da177e4SLinus Torvalds header->class, header->type);
1351da177e4SLinus Torvalds return NULL;
1361da177e4SLinus Torvalds }
1371da177e4SLinus Torvalds
1381da177e4SLinus Torvalds printk("%s*** %s:\n"
1391da177e4SLinus Torvalds " CLASS %d, TYPE %d\n",
1401da177e4SLinus Torvalds err_print_prefix,
1411da177e4SLinus Torvalds name,
1421da177e4SLinus Torvalds header->class, header->type);
1431da177e4SLinus Torvalds el_print_timestamp(×tamp);
1441da177e4SLinus Torvalds
1451da177e4SLinus Torvalds /*
1461da177e4SLinus Torvalds * Process the subpackets
1471da177e4SLinus Torvalds */
1481da177e4SLinus Torvalds el_process_subpackets(header, packet_count);
1491da177e4SLinus Torvalds
1501da177e4SLinus Torvalds /* return the next header */
1511da177e4SLinus Torvalds header = (struct el_subpacket *)
1521da177e4SLinus Torvalds ((unsigned long)header + header->length + length);
1531da177e4SLinus Torvalds return header;
1541da177e4SLinus Torvalds }
1551da177e4SLinus Torvalds
1561da177e4SLinus Torvalds static struct el_subpacket *
el_process_subpacket_reg(struct el_subpacket * header)1571da177e4SLinus Torvalds el_process_subpacket_reg(struct el_subpacket *header)
1581da177e4SLinus Torvalds {
1591da177e4SLinus Torvalds struct el_subpacket *next = NULL;
1601da177e4SLinus Torvalds struct el_subpacket_handler *h = subpacket_handler_list;
1611da177e4SLinus Torvalds
1621da177e4SLinus Torvalds for (; h && h->class != header->class; h = h->next);
1631da177e4SLinus Torvalds if (h) next = h->handler(header);
1641da177e4SLinus Torvalds
1651da177e4SLinus Torvalds return next;
1661da177e4SLinus Torvalds }
1671da177e4SLinus Torvalds
1681da177e4SLinus Torvalds void
el_print_timestamp(union el_timestamp * timestamp)1691da177e4SLinus Torvalds el_print_timestamp(union el_timestamp *timestamp)
1701da177e4SLinus Torvalds {
1711da177e4SLinus Torvalds if (timestamp->as_int)
1721da177e4SLinus Torvalds printk("%s TIMESTAMP: %d/%d/%02d %d:%02d:%0d\n",
1731da177e4SLinus Torvalds err_print_prefix,
1741da177e4SLinus Torvalds timestamp->b.month, timestamp->b.day,
1751da177e4SLinus Torvalds timestamp->b.year, timestamp->b.hour,
1761da177e4SLinus Torvalds timestamp->b.minute, timestamp->b.second);
1771da177e4SLinus Torvalds }
1781da177e4SLinus Torvalds
1791da177e4SLinus Torvalds void
el_process_subpackets(struct el_subpacket * header,int packet_count)1801da177e4SLinus Torvalds el_process_subpackets(struct el_subpacket *header, int packet_count)
1811da177e4SLinus Torvalds {
1821da177e4SLinus Torvalds struct el_subpacket *subpacket;
1831da177e4SLinus Torvalds int i;
1841da177e4SLinus Torvalds
1851da177e4SLinus Torvalds subpacket = (struct el_subpacket *)
1861da177e4SLinus Torvalds ((unsigned long)header + header->length);
1871da177e4SLinus Torvalds
1881da177e4SLinus Torvalds for (i = 0; subpacket && i < packet_count; i++) {
1891da177e4SLinus Torvalds printk("%sPROCESSING SUBPACKET %d\n", err_print_prefix, i);
1901da177e4SLinus Torvalds subpacket = el_process_subpacket(subpacket);
1911da177e4SLinus Torvalds }
1921da177e4SLinus Torvalds }
1931da177e4SLinus Torvalds
1941da177e4SLinus Torvalds struct el_subpacket *
el_process_subpacket(struct el_subpacket * header)1951da177e4SLinus Torvalds el_process_subpacket(struct el_subpacket *header)
1961da177e4SLinus Torvalds {
1971da177e4SLinus Torvalds struct el_subpacket *next = NULL;
1981da177e4SLinus Torvalds
1991da177e4SLinus Torvalds switch(header->class) {
2001da177e4SLinus Torvalds case EL_CLASS__TERMINATION:
2011da177e4SLinus Torvalds /* Termination packet, there are no more */
2021da177e4SLinus Torvalds break;
2031da177e4SLinus Torvalds case EL_CLASS__HEADER:
2041da177e4SLinus Torvalds next = el_process_header_subpacket(header);
2051da177e4SLinus Torvalds break;
2061da177e4SLinus Torvalds default:
2071da177e4SLinus Torvalds if (NULL == (next = el_process_subpacket_reg(header))) {
2081da177e4SLinus Torvalds printk("%s** Unexpected header CLASS %d TYPE %d"
2091da177e4SLinus Torvalds " -- aborting.\n",
2101da177e4SLinus Torvalds err_print_prefix,
2111da177e4SLinus Torvalds header->class, header->type);
2121da177e4SLinus Torvalds }
2131da177e4SLinus Torvalds break;
2141da177e4SLinus Torvalds }
2151da177e4SLinus Torvalds
2161da177e4SLinus Torvalds return next;
2171da177e4SLinus Torvalds }
2181da177e4SLinus Torvalds
2191da177e4SLinus Torvalds void
el_annotate_subpacket(struct el_subpacket * header)2201da177e4SLinus Torvalds el_annotate_subpacket(struct el_subpacket *header)
2211da177e4SLinus Torvalds {
2221da177e4SLinus Torvalds struct el_subpacket_annotation *a;
2231da177e4SLinus Torvalds char **annotation = NULL;
2241da177e4SLinus Torvalds
2251da177e4SLinus Torvalds for (a = subpacket_annotation_list; a; a = a->next) {
2261da177e4SLinus Torvalds if (a->class == header->class &&
2271da177e4SLinus Torvalds a->type == header->type &&
2281da177e4SLinus Torvalds a->revision == header->revision) {
2291da177e4SLinus Torvalds /*
2301da177e4SLinus Torvalds * We found the annotation
2311da177e4SLinus Torvalds */
2321da177e4SLinus Torvalds annotation = a->annotation;
2331da177e4SLinus Torvalds printk("%s %s\n", err_print_prefix, a->description);
2341da177e4SLinus Torvalds break;
2351da177e4SLinus Torvalds }
2361da177e4SLinus Torvalds }
2371da177e4SLinus Torvalds
2381da177e4SLinus Torvalds mchk_dump_mem(header, header->length, annotation);
2391da177e4SLinus Torvalds }
2401da177e4SLinus Torvalds
2411da177e4SLinus Torvalds static void __init
cdl_process_console_data_log(int cpu,struct percpu_struct * pcpu)2421da177e4SLinus Torvalds cdl_process_console_data_log(int cpu, struct percpu_struct *pcpu)
2431da177e4SLinus Torvalds {
2441da177e4SLinus Torvalds struct el_subpacket *header = (struct el_subpacket *)
2451da177e4SLinus Torvalds (IDENT_ADDR | pcpu->console_data_log_pa);
2461da177e4SLinus Torvalds int err;
2471da177e4SLinus Torvalds
2481da177e4SLinus Torvalds printk("%s******* CONSOLE DATA LOG FOR CPU %d. *******\n"
2491da177e4SLinus Torvalds "*** Error(s) were logged on a previous boot\n",
2501da177e4SLinus Torvalds err_print_prefix, cpu);
2511da177e4SLinus Torvalds
2521da177e4SLinus Torvalds for (err = 0; header && (header->class != EL_CLASS__TERMINATION); err++)
2531da177e4SLinus Torvalds header = el_process_subpacket(header);
2541da177e4SLinus Torvalds
2551da177e4SLinus Torvalds /* let the console know it's ok to clear the error(s) at restart */
2561da177e4SLinus Torvalds pcpu->console_data_log_pa = 0;
2571da177e4SLinus Torvalds
2581da177e4SLinus Torvalds printk("%s*** %d total error(s) logged\n"
2591da177e4SLinus Torvalds "**** END OF CONSOLE DATA LOG FOR CPU %d ****\n",
2601da177e4SLinus Torvalds err_print_prefix, err, cpu);
2611da177e4SLinus Torvalds }
2621da177e4SLinus Torvalds
2631da177e4SLinus Torvalds void __init
cdl_check_console_data_log(void)2641da177e4SLinus Torvalds cdl_check_console_data_log(void)
2651da177e4SLinus Torvalds {
2661da177e4SLinus Torvalds struct percpu_struct *pcpu;
2671da177e4SLinus Torvalds unsigned long cpu;
2681da177e4SLinus Torvalds
2691da177e4SLinus Torvalds for (cpu = 0; cpu < hwrpb->nr_processors; cpu++) {
2701da177e4SLinus Torvalds pcpu = (struct percpu_struct *)
2711da177e4SLinus Torvalds ((unsigned long)hwrpb + hwrpb->processor_offset
2721da177e4SLinus Torvalds + cpu * hwrpb->processor_size);
2731da177e4SLinus Torvalds if (pcpu->console_data_log_pa)
2741da177e4SLinus Torvalds cdl_process_console_data_log(cpu, pcpu);
2751da177e4SLinus Torvalds }
2761da177e4SLinus Torvalds
2771da177e4SLinus Torvalds }
2781da177e4SLinus Torvalds
2791da177e4SLinus Torvalds int __init
cdl_register_subpacket_annotation(struct el_subpacket_annotation * new)2801da177e4SLinus Torvalds cdl_register_subpacket_annotation(struct el_subpacket_annotation *new)
2811da177e4SLinus Torvalds {
2821da177e4SLinus Torvalds struct el_subpacket_annotation *a = subpacket_annotation_list;
2831da177e4SLinus Torvalds
2841da177e4SLinus Torvalds if (a == NULL) subpacket_annotation_list = new;
2851da177e4SLinus Torvalds else {
2861da177e4SLinus Torvalds for (; a->next != NULL; a = a->next) {
2871da177e4SLinus Torvalds if ((a->class == new->class && a->type == new->type) ||
2881da177e4SLinus Torvalds a == new) {
2891da177e4SLinus Torvalds printk("Attempted to re-register "
2901da177e4SLinus Torvalds "subpacket annotation\n");
2911da177e4SLinus Torvalds return -EINVAL;
2921da177e4SLinus Torvalds }
2931da177e4SLinus Torvalds }
2941da177e4SLinus Torvalds a->next = new;
2951da177e4SLinus Torvalds }
2961da177e4SLinus Torvalds new->next = NULL;
2971da177e4SLinus Torvalds
2981da177e4SLinus Torvalds return 0;
2991da177e4SLinus Torvalds }
3001da177e4SLinus Torvalds
3011da177e4SLinus Torvalds int __init
cdl_register_subpacket_handler(struct el_subpacket_handler * new)3021da177e4SLinus Torvalds cdl_register_subpacket_handler(struct el_subpacket_handler *new)
3031da177e4SLinus Torvalds {
3041da177e4SLinus Torvalds struct el_subpacket_handler *h = subpacket_handler_list;
3051da177e4SLinus Torvalds
3061da177e4SLinus Torvalds if (h == NULL) subpacket_handler_list = new;
3071da177e4SLinus Torvalds else {
3081da177e4SLinus Torvalds for (; h->next != NULL; h = h->next) {
3091da177e4SLinus Torvalds if (h->class == new->class || h == new) {
3101da177e4SLinus Torvalds printk("Attempted to re-register "
3111da177e4SLinus Torvalds "subpacket handler\n");
3121da177e4SLinus Torvalds return -EINVAL;
3131da177e4SLinus Torvalds }
3141da177e4SLinus Torvalds }
3151da177e4SLinus Torvalds h->next = new;
3161da177e4SLinus Torvalds }
3171da177e4SLinus Torvalds new->next = NULL;
3181da177e4SLinus Torvalds
3191da177e4SLinus Torvalds return 0;
3201da177e4SLinus Torvalds }
3211da177e4SLinus Torvalds
322