patch-2.3.43 linux/arch/ia64/kernel/mca.c
Next file: linux/arch/ia64/kernel/mca_asm.S
Previous file: linux/arch/ia64/kernel/machvec.c
Back to the patch index
Back to the overall index
- Lines: 843
- Date:
Sun Feb 6 18:42:40 2000
- Orig file:
v2.3.42/linux/arch/ia64/kernel/mca.c
- Orig date:
Wed Dec 31 16:00:00 1969
diff -u --recursive --new-file v2.3.42/linux/arch/ia64/kernel/mca.c linux/arch/ia64/kernel/mca.c
@@ -0,0 +1,842 @@
+/*
+ * File: mca.c
+ * Purpose: Generic MCA handling layer
+ *
+ * Copyright (C) 1999 Silicon Graphics, Inc.
+ * Copyright (C) Vijay Chander(vijay@engr.sgi.com)
+ */
+#include <linux/types.h>
+#include <linux/init.h>
+#include <linux/sched.h>
+#include <asm/page.h>
+#include <asm/ptrace.h>
+#include <asm/system.h>
+#include <asm/sal.h>
+#include <asm/mca.h>
+#include <asm/spinlock.h>
+#include <asm/irq.h>
+#include <asm/machvec.h>
+
+
+ia64_mc_info_t ia64_mc_info;
+ia64_mca_sal_to_os_state_t ia64_sal_to_os_handoff_state;
+ia64_mca_os_to_sal_state_t ia64_os_to_sal_handoff_state;
+u64 ia64_mca_proc_state_dump[256];
+u64 ia64_mca_stack[1024];
+u64 ia64_mca_stackframe[32];
+u64 ia64_mca_bspstore[1024];
+
+static void ia64_mca_cmc_vector_setup(int enable,
+ int_vector_t cmc_vector);
+static void ia64_mca_wakeup_ipi_wait(void);
+static void ia64_mca_wakeup(int cpu);
+static void ia64_mca_wakeup_all(void);
+static void ia64_log_init(int,int);
+static void ia64_log_get(int,int, prfunc_t);
+static void ia64_log_clear(int,int,int, prfunc_t);
+
+/*
+ * ia64_mca_cmc_vector_setup
+ * Setup the correctable machine check vector register in the processor
+ * Inputs
+ * Enable (1 - enable cmc interrupt , 0 - disable)
+ * CMC handler entry point (if enabled)
+ *
+ * Outputs
+ * None
+ */
+static void
+ia64_mca_cmc_vector_setup(int enable,
+ int_vector_t cmc_vector)
+{
+ cmcv_reg_t cmcv;
+
+ cmcv.cmcv_regval = 0;
+ cmcv.cmcv_mask = enable;
+ cmcv.cmcv_vector = cmc_vector;
+ ia64_set_cmcv(cmcv.cmcv_regval);
+}
+
+
+#if defined(MCA_TEST)
+
+sal_log_processor_info_t slpi_buf;
+
+void
+mca_test(void)
+{
+ slpi_buf.slpi_valid.slpi_psi = 1;
+ slpi_buf.slpi_valid.slpi_cache_check = 1;
+ slpi_buf.slpi_valid.slpi_tlb_check = 1;
+ slpi_buf.slpi_valid.slpi_bus_check = 1;
+ slpi_buf.slpi_valid.slpi_minstate = 1;
+ slpi_buf.slpi_valid.slpi_bank1_gr = 1;
+ slpi_buf.slpi_valid.slpi_br = 1;
+ slpi_buf.slpi_valid.slpi_cr = 1;
+ slpi_buf.slpi_valid.slpi_ar = 1;
+ slpi_buf.slpi_valid.slpi_rr = 1;
+ slpi_buf.slpi_valid.slpi_fr = 1;
+
+ ia64_os_mca_dispatch();
+}
+
+#endif /* #if defined(MCA_TEST) */
+
+/*
+ * mca_init
+ * Do all the mca specific initialization on a per-processor basis.
+ *
+ * 1. Register spinloop and wakeup request interrupt vectors
+ *
+ * 2. Register OS_MCA handler entry point
+ *
+ * 3. Register OS_INIT handler entry point
+ *
+ * 4. Initialize CMCV register to enable/disable CMC interrupt on the
+ * processor and hook a handler in the platform-specific mca_init.
+ *
+ * 5. Initialize MCA/CMC/INIT related log buffers maintained by the OS.
+ *
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void __init
+mca_init(void)
+{
+ int i;
+
+ MCA_DEBUG("mca_init : begin\n");
+ /* Clear the Rendez checkin flag for all cpus */
+ for(i = 0 ; i < IA64_MAXCPUS; i++)
+ ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+
+ /* NOTE : The actual irqs for the rendez, wakeup and
+ * cmc interrupts are requested in the platform-specific
+ * mca initialization code.
+ */
+ /*
+ * Register the rendezvous spinloop and wakeup mechanism with SAL
+ */
+
+ /* Register the rendezvous interrupt vector with SAL */
+ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT,
+ SAL_MC_PARAM_MECHANISM_INT,
+ IA64_MCA_RENDEZ_INT_VECTOR,
+ IA64_MCA_RENDEZ_TIMEOUT))
+ return;
+
+ /* Register the wakeup interrupt vector with SAL */
+ if (ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP,
+ SAL_MC_PARAM_MECHANISM_INT,
+ IA64_MCA_WAKEUP_INT_VECTOR,
+ 0))
+ return;
+
+ MCA_DEBUG("mca_init : registered mca rendezvous spinloop and wakeup mech.\n");
+ /*
+ * Setup the correctable machine check vector
+ */
+ ia64_mca_cmc_vector_setup(IA64_CMC_INT_ENABLE,
+ IA64_MCA_CMC_INT_VECTOR);
+
+ MCA_DEBUG("mca_init : correctable mca vector setup done\n");
+
+ ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch);
+ ia64_mc_info.imi_mca_handler_size =
+ __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch);
+ /* Register the os mca handler with SAL */
+ if (ia64_sal_set_vectors(SAL_VECTOR_OS_MCA,
+ ia64_mc_info.imi_mca_handler,
+ __pa(ia64_get_gp()),
+ ia64_mc_info.imi_mca_handler_size,
+ 0,0,0))
+
+ return;
+
+ MCA_DEBUG("mca_init : registered os mca handler with SAL\n");
+
+ ia64_mc_info.imi_monarch_init_handler = __pa(ia64_monarch_init_handler);
+ ia64_mc_info.imi_monarch_init_handler_size = IA64_INIT_HANDLER_SIZE;
+ ia64_mc_info.imi_slave_init_handler = __pa(ia64_slave_init_handler);
+ ia64_mc_info.imi_slave_init_handler_size = IA64_INIT_HANDLER_SIZE;
+ /* Register the os init handler with SAL */
+ if (ia64_sal_set_vectors(SAL_VECTOR_OS_INIT,
+ ia64_mc_info.imi_monarch_init_handler,
+ __pa(ia64_get_gp()),
+ ia64_mc_info.imi_monarch_init_handler_size,
+ ia64_mc_info.imi_slave_init_handler,
+ __pa(ia64_get_gp()),
+ ia64_mc_info.imi_slave_init_handler_size))
+
+
+ return;
+
+ MCA_DEBUG("mca_init : registered os init handler with SAL\n");
+
+ /* Initialize the areas set aside by the OS to buffer the
+ * platform/processor error states for MCA/INIT/CMC
+ * handling.
+ */
+ ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR);
+ ia64_log_init(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM);
+ ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PROCESSOR);
+ ia64_log_init(SAL_INFO_TYPE_INIT, SAL_SUB_INFO_TYPE_PLATFORM);
+ ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR);
+ ia64_log_init(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
+
+ mca_init_platform();
+
+ MCA_DEBUG("mca_init : platform-specific mca handling setup done\n");
+
+#if defined(MCA_TEST)
+ mca_test();
+#endif /* #if defined(MCA_TEST) */
+
+ printk("Mca related initialization done\n");
+}
+
+/*
+ * ia64_mca_wakeup_ipi_wait
+ * Wait for the inter-cpu interrupt to be sent by the
+ * monarch processor once it is done with handling the
+ * MCA.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void
+ia64_mca_wakeup_ipi_wait(void)
+{
+ int irr_num = (IA64_MCA_WAKEUP_INT_VECTOR >> 6);
+ int irr_bit = (IA64_MCA_WAKEUP_INT_VECTOR & 0x3f);
+ u64 irr = 0;
+
+ do {
+ switch(irr_num) {
+ case 0:
+ irr = ia64_get_irr0();
+ break;
+ case 1:
+ irr = ia64_get_irr1();
+ break;
+ case 2:
+ irr = ia64_get_irr2();
+ break;
+ case 3:
+ irr = ia64_get_irr3();
+ break;
+ }
+ } while (!(irr & (1 << irr_bit))) ;
+}
+
+/*
+ * ia64_mca_wakeup
+ * Send an inter-cpu interrupt to wake-up a particular cpu
+ * and mark that cpu to be out of rendez.
+ * Inputs
+ * cpuid
+ * Outputs
+ * None
+ */
+void
+ia64_mca_wakeup(int cpu)
+{
+ ipi_send(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT);
+ ia64_mc_info.imi_rendez_checkin[cpu] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE;
+
+}
+/*
+ * ia64_mca_wakeup_all
+ * Wakeup all the cpus which have rendez'ed previously.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void
+ia64_mca_wakeup_all(void)
+{
+ int cpu;
+
+ /* Clear the Rendez checkin flag for all cpus */
+ for(cpu = 0 ; cpu < IA64_MAXCPUS; cpu++)
+ if (ia64_mc_info.imi_rendez_checkin[cpu] == IA64_MCA_RENDEZ_CHECKIN_DONE)
+ ia64_mca_wakeup(cpu);
+
+}
+/*
+ * ia64_mca_rendez_interrupt_handler
+ * This is handler used to put slave processors into spinloop
+ * while the monarch processor does the mca handling and later
+ * wake each slave up once the monarch is done.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void
+ia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs)
+{
+ int flags;
+ /* Mask all interrupts */
+ save_and_cli(flags);
+
+ ia64_mc_info.imi_rendez_checkin[ia64_get_cpuid(0)] = IA64_MCA_RENDEZ_CHECKIN_DONE;
+ /* Register with the SAL monarch that the slave has
+ * reached SAL
+ */
+ ia64_sal_mc_rendez();
+
+ /* Wait for the wakeup IPI from the monarch
+ * This waiting is done by polling on the wakeup-interrupt
+ * vector bit in the processor's IRRs
+ */
+ ia64_mca_wakeup_ipi_wait();
+
+ /* Enable all interrupts */
+ restore_flags(flags);
+
+
+}
+
+
+/*
+ * ia64_mca_wakeup_int_handler
+ * The interrupt handler for processing the inter-cpu interrupt to the
+ * slave cpu which was spinning in the rendez loop.
+ * Since this spinning is done by turning off the interrupts and
+ * polling on the wakeup-interrupt bit in the IRR, there is
+ * nothing useful to be done in the handler.
+ * Inputs
+ * wakeup_irq (Wakeup-interrupt bit)
+ * arg (Interrupt handler specific argument)
+ * ptregs (Exception frame at the time of the interrupt)
+ * Outputs
+ *
+ */
+void
+ia64_mca_wakeup_int_handler(int wakeup_irq, void *arg, struct pt_regs *ptregs)
+{
+
+}
+
+/*
+ * ia64_return_to_sal_check
+ * This is function called before going back from the OS_MCA handler
+ * to the OS_MCA dispatch code which finally takes the control back
+ * to the SAL.
+ * The main purpose of this routine is to setup the OS_MCA to SAL
+ * return state which can be used by the OS_MCA dispatch code
+ * just before going back to SAL.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+
+void
+ia64_return_to_sal_check(void)
+{
+ /* Copy over some relevant stuff from the sal_to_os_mca_handoff
+ * so that it can be used at the time of os_mca_to_sal_handoff
+ */
+ ia64_os_to_sal_handoff_state.imots_sal_gp =
+ ia64_sal_to_os_handoff_state.imsto_sal_gp;
+
+ ia64_os_to_sal_handoff_state.imots_sal_check_ra =
+ ia64_sal_to_os_handoff_state.imsto_sal_check_ra;
+
+ /* For now ignore the MCA */
+ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_CORRECTED;
+}
+/*
+ * ia64_mca_ucmc_handler
+ * This is uncorrectable machine check handler called from OS_MCA
+ * dispatch code which is in turn called from SAL_CHECK().
+ * This is the place where the core of OS MCA handling is done.
+ * Right now the logs are extracted and displayed in a well-defined
+ * format. This handler code is supposed to be run only on the
+ * monarch processor. Once the monarch is done with MCA handling
+ * further MCA logging is enabled by clearing logs.
+ * Monarch also has the duty of sending wakeup-IPIs to pull the
+ * slave processors out of rendez. spinloop.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void
+ia64_mca_ucmc_handler(void)
+{
+
+ /* Get the MCA processor log */
+ ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+ /* Get the MCA platform log */
+ ia64_log_get(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
+
+ ia64_log_print(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+
+ /*
+ * Do some error handling - Platform-specific mca handler is called at this point
+ */
+
+ mca_handler_platform() ;
+
+ /* Clear the SAL MCA logs */
+ ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PROCESSOR, 1, printk);
+ ia64_log_clear(SAL_INFO_TYPE_MCA, SAL_SUB_INFO_TYPE_PLATFORM, 1, printk);
+
+ /* Wakeup all the processors which are spinning in the rendezvous
+ * loop.
+ */
+ ia64_mca_wakeup_all();
+ ia64_return_to_sal_check();
+}
+
+/*
+ * SAL to OS entry point for INIT on the monarch processor
+ * This has been defined for registration purposes with SAL
+ * as a part of mca_init.
+ */
+void
+ia64_monarch_init_handler()
+{
+}
+/*
+ * SAL to OS entry point for INIT on the slave processor
+ * This has been defined for registration purposes with SAL
+ * as a part of mca_init.
+ */
+
+void
+ia64_slave_init_handler()
+{
+}
+/*
+ * ia64_mca_cmc_int_handler
+ * This is correctable machine check interrupt handler.
+ * Right now the logs are extracted and displayed in a well-defined
+ * format.
+ * Inputs
+ * None
+ * Outputs
+ * None
+ */
+void
+ia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs)
+{
+ /* Get the CMC processor log */
+ ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+ /* Get the CMC platform log */
+ ia64_log_get(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM, (prfunc_t)printk);
+
+
+ ia64_log_print(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR, (prfunc_t)printk);
+ cmci_handler_platform(cmc_irq, arg, ptregs);
+
+ /* Clear the CMC SAL logs now that they have been saved in the OS buffer */
+ ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PROCESSOR);
+ ia64_sal_clear_state_info(SAL_INFO_TYPE_CMC, SAL_SUB_INFO_TYPE_PLATFORM);
+}
+
+/*
+ * IA64_MCA log support
+ */
+#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */
+#define IA64_MAX_LOG_TYPES 3 /* MCA, CMC, INIT */
+#define IA64_MAX_LOG_SUBTYPES 2 /* Processor, Platform */
+
+typedef struct ia64_state_log_s {
+ spinlock_t isl_lock;
+ int isl_index;
+ sal_log_header_t isl_log[IA64_MAX_LOGS];
+
+} ia64_state_log_t;
+
+static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES][IA64_MAX_LOG_SUBTYPES];
+
+#define IA64_LOG_LOCK_INIT(it, sit) spin_lock_init(&ia64_state_log[it][sit].isl_lock)
+#define IA64_LOG_LOCK(it, sit) spin_lock_irqsave(&ia64_state_log[it][sit].isl_lock, s)
+#define IA64_LOG_UNLOCK(it, sit) spin_unlock_irqrestore(&ia64_state_log[it][sit].isl_lock,\
+ s)
+#define IA64_LOG_NEXT_INDEX(it, sit) ia64_state_log[it][sit].isl_index
+#define IA64_LOG_CURR_INDEX(it, sit) 1 - ia64_state_log[it][sit].isl_index
+#define IA64_LOG_INDEX_INC(it, sit) \
+ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
+#define IA64_LOG_INDEX_DEC(it, sit) \
+ ia64_state_log[it][sit].isl_index = 1 - ia64_state_log[it][sit].isl_index
+#define IA64_LOG_NEXT_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_NEXT_INDEX(it,sit)]))
+#define IA64_LOG_CURR_BUFFER(it, sit) (void *)(&(ia64_state_log[it][sit].isl_log[IA64_LOG_CURR_INDEX(it,sit)]))
+
+/*
+ * ia64_log_init
+ * Reset the OS ia64 log buffer
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC})
+ * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ * Outputs : None
+ */
+void
+ia64_log_init(int sal_info_type, int sal_sub_info_type)
+{
+ IA64_LOG_LOCK_INIT(sal_info_type, sal_sub_info_type);
+ IA64_LOG_NEXT_INDEX(sal_info_type, sal_sub_info_type) = 0;
+ memset(IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type), 0,
+ sizeof(sal_log_header_t) * IA64_MAX_LOGS);
+}
+
+/*
+ * ia64_log_get
+ * Get the current MCA log from SAL and copy it into the OS log buffer.
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC})
+ * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ * Outputs : None
+ *
+ */
+void
+ia64_log_get(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
+{
+ sal_log_header_t *log_buffer;
+ int s;
+
+ IA64_LOG_LOCK(sal_info_type, sal_sub_info_type);
+
+
+ /* Get the process state information */
+ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type, sal_sub_info_type);
+
+ if (ia64_sal_get_state_info(sal_info_type, sal_sub_info_type ,(u64 *)log_buffer))
+ prfunc("ia64_mca_log_get : Getting processor log failed\n");
+
+ IA64_LOG_INDEX_INC(sal_info_type, sal_sub_info_type);
+
+ IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
+
+}
+
+/*
+ * ia64_log_clear
+ * Clear the current MCA log from SAL and dpending on the clear_os_buffer flags
+ * clear the OS log buffer also
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC})
+ * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ * clear_os_buffer
+ * prfunc (print function)
+ * Outputs : None
+ *
+ */
+void
+ia64_log_clear(int sal_info_type, int sal_sub_info_type, int clear_os_buffer, prfunc_t prfunc)
+{
+ if (ia64_sal_clear_state_info(sal_info_type, sal_sub_info_type))
+ prfunc("ia64_mca_log_get : Clearing processor log failed\n");
+
+ if (clear_os_buffer) {
+ sal_log_header_t *log_buffer;
+ int s;
+
+ IA64_LOG_LOCK(sal_info_type, sal_sub_info_type);
+
+ /* Get the process state information */
+ log_buffer = IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type);
+
+ memset(log_buffer, 0, sizeof(sal_log_header_t));
+
+ IA64_LOG_INDEX_DEC(sal_info_type, sal_sub_info_type);
+
+ IA64_LOG_UNLOCK(sal_info_type, sal_sub_info_type);
+ }
+
+}
+
+/*
+ * ia64_log_processor_regs_print
+ * Print the contents of the saved processor register(s) in the format
+ * <reg_prefix>[<index>] <value>
+ *
+ * Inputs : regs (Register save buffer)
+ * reg_num (# of registers)
+ * reg_class (application/banked/control/bank1_general)
+ * reg_prefix (ar/br/cr/b1_gr)
+ * Outputs : None
+ *
+ */
+void
+ia64_log_processor_regs_print(u64 *regs,
+ int reg_num,
+ char *reg_class,
+ char *reg_prefix,
+ prfunc_t prfunc)
+{
+ int i;
+
+ prfunc("+%s Registers\n", reg_class);
+ for (i = 0; i < reg_num; i++)
+ prfunc("+ %s[%d] 0x%lx\n", reg_prefix, i, regs[i]);
+}
+
+static char *pal_mesi_state[] = {
+ "Invalid",
+ "Shared",
+ "Exclusive",
+ "Modified",
+ "Reserved1",
+ "Reserved2",
+ "Reserved3",
+ "Reserved4"
+};
+
+static char *pal_cache_op[] = {
+ "Unknown",
+ "Move in",
+ "Cast out",
+ "Coherency check",
+ "Internal",
+ "Instruction fetch",
+ "Implicit Writeback",
+ "Reserved"
+};
+
+/*
+ * ia64_log_cache_check_info_print
+ * Display the machine check information related to cache error(s).
+ * Inputs : i (Multiple errors are logged, i - index of logged error)
+ * info (Machine check info logged by the PAL and later
+ * captured by the SAL)
+ * target_addr (Address which caused the cache error)
+ * Outputs : None
+ */
+void
+ia64_log_cache_check_info_print(int i,
+ pal_cache_check_info_t info,
+ u64 target_addr,
+ prfunc_t prfunc)
+{
+ prfunc("+ Cache check info[%d]\n+", i);
+ prfunc(" Level: L%d",info.level);
+ if (info.mv)
+ prfunc(" ,Mesi: %s",pal_mesi_state[info.mesi]);
+ prfunc(" ,Index: %d,", info.index);
+ if (info.ic)
+ prfunc(" ,Cache: Instruction");
+ if (info.dc)
+ prfunc(" ,Cache: Data");
+ if (info.tl)
+ prfunc(" ,Line: Tag");
+ if (info.dl)
+ prfunc(" ,Line: Data");
+ prfunc(" ,Operation: %s,", pal_cache_op[info.op]);
+ if (info.wv)
+ prfunc(" ,Way: %d,", info.way);
+ if (info.tv)
+ prfunc(" ,Target Addr: 0x%lx", target_addr);
+ if (info.mc)
+ prfunc(" ,MC: Corrected");
+ prfunc("\n");
+}
+
+/*
+ * ia64_log_tlb_check_info_print
+ * Display the machine check information related to tlb error(s).
+ * Inputs : i (Multiple errors are logged, i - index of logged error)
+ * info (Machine check info logged by the PAL and later
+ * captured by the SAL)
+ * Outputs : None
+ */
+
+void
+ia64_log_tlb_check_info_print(int i,
+ pal_tlb_check_info_t info,
+ prfunc_t prfunc)
+{
+ prfunc("+ TLB Check Info [%d]\n+", i);
+ if (info.itc)
+ prfunc(" Failure: Instruction Translation Cache");
+ if (info.dtc)
+ prfunc(" Failure: Data Translation Cache");
+ if (info.itr) {
+ prfunc(" Failure: Instruction Translation Register");
+ prfunc(" ,Slot: %d", info.tr_slot);
+ }
+ if (info.dtr) {
+ prfunc(" Failure: Data Translation Register");
+ prfunc(" ,Slot: %d", info.tr_slot);
+ }
+ if (info.mc)
+ prfunc(" ,MC: Corrected");
+ prfunc("\n");
+}
+
+/*
+ * ia64_log_bus_check_info_print
+ * Display the machine check information related to bus error(s).
+ * Inputs : i (Multiple errors are logged, i - index of logged error)
+ * info (Machine check info logged by the PAL and later
+ * captured by the SAL)
+ * req_addr (Address of the requestor of the transaction)
+ * resp_addr (Address of the responder of the transaction)
+ * target_addr (Address where the data was to be delivered to or
+ * obtained from)
+ * Outputs : None
+ */
+void
+ia64_log_bus_check_info_print(int i,
+ pal_bus_check_info_t info,
+ u64 req_addr,
+ u64 resp_addr,
+ u64 targ_addr,
+ prfunc_t prfunc)
+{
+ prfunc("+ BUS Check Info [%d]\n+", i);
+ prfunc(" Status Info: %d", info.bsi);
+ prfunc(" ,Severity: %d", info.sev);
+ prfunc(" ,Transaction Type: %d", info.type);
+ prfunc(" ,Transaction Size: %d", info.size);
+ if (info.cc)
+ prfunc(" ,Cache-cache-transfer");
+ if (info.ib)
+ prfunc(" ,Error: Internal");
+ if (info.eb)
+ prfunc(" ,Error: External");
+ if (info.mc)
+ prfunc(" ,MC: Corrected");
+ if (info.tv)
+ prfunc(" ,Target Address: 0x%lx", targ_addr);
+ if (info.rq)
+ prfunc(" ,Requestor Address: 0x%lx", req_addr);
+ if (info.tv)
+ prfunc(" ,Responder Address: 0x%lx", resp_addr);
+ prfunc("\n");
+}
+
+/*
+ * ia64_log_processor_info_print
+ * Display the processor-specific information logged by PAL as a part
+ * of MCA or INIT or CMC.
+ * Inputs : lh (Pointer of the sal log header which specifies the format
+ * of SAL state info as specified by the SAL spec).
+ * Outputs : None
+ */
+void
+ia64_log_processor_info_print(sal_log_header_t *lh, prfunc_t prfunc)
+{
+ sal_log_processor_info_t *slpi;
+ int i;
+
+ if (!lh)
+ return;
+
+ if (lh->slh_log_type != SAL_SUB_INFO_TYPE_PROCESSOR)
+ return;
+
+#if defined(MCA_TEST)
+ slpi = &slpi_buf;
+#else
+ slpi = (sal_log_processor_info_t *)lh->slh_log_dev_spec_info;
+#endif /#if defined(MCA_TEST) */
+
+ if (!slpi) {
+ prfunc("No Processor Error Log found\n");
+ return;
+ }
+
+ /* Print branch register contents if valid */
+ if (slpi->slpi_valid.slpi_br)
+ ia64_log_processor_regs_print(slpi->slpi_br, 8, "Branch", "br", prfunc);
+
+ /* Print control register contents if valid */
+ if (slpi->slpi_valid.slpi_cr)
+ ia64_log_processor_regs_print(slpi->slpi_cr, 128, "Control", "cr", prfunc);
+
+ /* Print application register contents if valid */
+ if (slpi->slpi_valid.slpi_ar)
+ ia64_log_processor_regs_print(slpi->slpi_br, 128, "Application", "ar", prfunc);
+
+ /* Print region register contents if valid */
+ if (slpi->slpi_valid.slpi_rr)
+ ia64_log_processor_regs_print(slpi->slpi_rr, 8, "Region", "rr", prfunc);
+
+ /* Print floating-point register contents if valid */
+ if (slpi->slpi_valid.slpi_fr)
+ ia64_log_processor_regs_print(slpi->slpi_fr, 128, "Floating-point", "fr",
+ prfunc);
+
+ /* Print bank1-gr NAT register contents if valid */
+ ia64_log_processor_regs_print(&slpi->slpi_bank1_nat_bits, 1, "NAT", "nat", prfunc);
+
+ /* Print bank 1 register contents if valid */
+ if (slpi->slpi_valid.slpi_bank1_gr)
+ ia64_log_processor_regs_print(slpi->slpi_bank1_gr, 16, "Bank1-General", "gr",
+ prfunc);
+
+ /* Print the cache check information if any*/
+ for (i = 0 ; i < MAX_CACHE_ERRORS; i++)
+ ia64_log_cache_check_info_print(i,
+ slpi->slpi_cache_check_info[i].slpi_cache_check,
+ slpi->slpi_cache_check_info[i].slpi_target_address,
+ prfunc);
+ /* Print the tlb check information if any*/
+ for (i = 0 ; i < MAX_TLB_ERRORS; i++)
+ ia64_log_tlb_check_info_print(i,slpi->slpi_tlb_check_info[i], prfunc);
+
+ /* Print the bus check information if any*/
+ for (i = 0 ; i < MAX_BUS_ERRORS; i++)
+ ia64_log_bus_check_info_print(i,
+ slpi->slpi_bus_check_info[i].slpi_bus_check,
+ slpi->slpi_bus_check_info[i].slpi_requestor_addr,
+ slpi->slpi_bus_check_info[i].slpi_responder_addr,
+ slpi->slpi_bus_check_info[i].slpi_target_addr,
+ prfunc);
+
+}
+
+/*
+ * ia64_log_print
+ * Display the contents of the OS error log information
+ * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC})
+ * sub_info_type (SAL_SUB_INFO_TYPE_{PROCESSOR,PLATFORM})
+ * Outputs : None
+ */
+void
+ia64_log_print(int sal_info_type, int sal_sub_info_type, prfunc_t prfunc)
+{
+ char *info_type, *sub_info_type;
+
+ switch(sal_info_type) {
+ case SAL_INFO_TYPE_MCA:
+ info_type = "MCA";
+ break;
+ case SAL_INFO_TYPE_INIT:
+ info_type = "INIT";
+ break;
+ case SAL_INFO_TYPE_CMC:
+ info_type = "CMC";
+ break;
+ default:
+ info_type = "UNKNOWN";
+ break;
+ }
+
+ switch(sal_sub_info_type) {
+ case SAL_SUB_INFO_TYPE_PROCESSOR:
+ sub_info_type = "PROCESSOR";
+ break;
+ case SAL_SUB_INFO_TYPE_PLATFORM:
+ sub_info_type = "PLATFORM";
+ break;
+ default:
+ sub_info_type = "UNKNOWN";
+ break;
+ }
+
+ prfunc("+BEGIN HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type);
+ if (sal_sub_info_type == SAL_SUB_INFO_TYPE_PROCESSOR)
+ ia64_log_processor_info_print(
+ IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),
+ prfunc);
+ else
+ log_print_platform(IA64_LOG_CURR_BUFFER(sal_info_type, sal_sub_info_type),prfunc);
+ prfunc("+END HARDWARE ERROR STATE [%s %s]\n", info_type, sub_info_type);
+}
FUNET's LINUX-ADM group, linux-adm@nic.funet.fi
TCL-scripts by Sam Shen (who was at: slshen@lbl.gov)