📄 mca.c
字号:
/* * File: mca.c * Purpose: Generic MCA handling layer * * Updated for latest kernel * Copyright (C) 2001 Intel * Copyright (C) Fred Lewis (frederick.v.lewis@intel.com) * * Copyright (C) 2000 Intel * Copyright (C) Chuck Fleckenstein (cfleck@co.intel.com) * * Copyright (C) 1999 Silicon Graphics, Inc. * Copyright (C) Vijay Chander(vijay@engr.sgi.com) * * 01/01/03 F. Lewis Added setup of CMCI and CPEI IRQs, logging of corrected * platform errors, completed code for logging of * corrected & uncorrected machine check errors, and * updated for conformance with Nov. 2000 revision of the * SAL 3.0 spec. * 00/03/29 C. Fleckenstein Fixed PAL/SAL update issues, began MCA bug fixes, logging issues, * added min save state dump, added INIT handler. */#include <linux/config.h>#include <linux/types.h>#include <linux/init.h>#include <linux/sched.h>#include <linux/interrupt.h>#include <linux/irq.h>#include <linux/smp_lock.h>#include <asm/machvec.h>#include <asm/page.h>#include <asm/ptrace.h>#include <asm/system.h>#include <asm/sal.h>#include <asm/mca.h>#include <asm/irq.h>#include <asm/hw_irq.h>#include <asm/acpi-ext.h>#undef MCA_PRT_XTRA_DATAtypedef struct ia64_fptr { unsigned long fp; unsigned long gp;} ia64_fptr_t;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[512];u64 ia64_mca_stack[1024];u64 ia64_mca_stackframe[32];u64 ia64_mca_bspstore[1024];u64 ia64_init_stack[INIT_TASK_SIZE] __attribute__((aligned(16)));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);extern void ia64_monarch_init_handler (void);extern void ia64_slave_init_handler (void);extern struct hw_interrupt_type irq_type_iosapic_level;static struct irqaction cmci_irqaction = { handler: ia64_mca_cmc_int_handler, flags: SA_INTERRUPT, name: "cmc_hndlr"};static struct irqaction mca_rdzv_irqaction = { handler: ia64_mca_rendez_int_handler, flags: SA_INTERRUPT, name: "mca_rdzv"};static struct irqaction mca_wkup_irqaction = { handler: ia64_mca_wakeup_int_handler, flags: SA_INTERRUPT, name: "mca_wkup"};static struct irqaction mca_cpe_irqaction = { handler: ia64_mca_cpe_int_handler, flags: SA_INTERRUPT, name: "cpe_hndlr"};/* * ia64_mca_log_sal_error_record * * This function retrieves a specified error record type from SAL, sends it to * the system log, and notifies SALs to clear the record from its non-volatile * memory. * * Inputs : sal_info_type (Type of error record MCA/CMC/CPE/INIT) * Outputs : None */voidia64_mca_log_sal_error_record(int sal_info_type){ /* Get the MCA error record */ if (!ia64_log_get(sal_info_type, (prfunc_t)printk)) return; // no record retrieved /* Log the error record */ ia64_log_print(sal_info_type, (prfunc_t)printk); /* Clear the CMC SAL logs now that they have been logged */ ia64_sal_clear_state_info(sal_info_type);}/* * hack for now, add platform dependent handlers * here */#ifndef PLATFORM_MCA_HANDLERSvoidmca_handler_platform (void){}voidia64_mca_cpe_int_handler (int cpe_irq, void *arg, struct pt_regs *ptregs){ IA64_MCA_DEBUG("ia64_mca_cpe_int_handler: received interrupt. vector = %#x\n", cpe_irq); /* Get the CMC error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CPE);}/* * This routine will be used to deal with platform specific handling * of the init, i.e. drop into the kernel debugger on server machine, * or if the processor is part of some parallel machine without a * console, then we would call the appropriate debug hooks here. */voidinit_handler_platform (struct pt_regs *regs){ /* if a kernel debugger is available call it here else just dump the registers */ show_regs(regs); /* dump the state info */ while (1); /* hang city if no debugger */}/* * ia64_mca_init_platform * * External entry for platform specific MCA initialization. * * Inputs * None * * Outputs * None */voidia64_mca_init_platform (void){}/* * ia64_mca_check_errors * * External entry to check for error records which may have been posted by SAL * for a prior failure which resulted in a machine shutdown before an the * error could be logged. This function must be called after the filesystem * is initialized. * * Inputs : None * * Outputs : None */voidia64_mca_check_errors (void){ /* * If there is an MCA error record pending, get it and log it. */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);}/* * ia64_mca_register_cpev * * Register the corrected platform error vector with SAL. * * Inputs * cpev Corrected Platform Error Vector number * * Outputs * None */static voidia64_mca_register_cpev (int cpev){ /* Register the CPE interrupt vector with SAL */ if (ia64_sal_mc_set_params(SAL_MC_PARAM_CPE_INT, SAL_MC_PARAM_MECHANISM_INT, cpev, 0, 0)) { printk("ia64_mca_platform_init: failed to register Corrected " "Platform Error interrupt vector with SAL.\n"); return; } IA64_MCA_DEBUG("ia64_mca_platform_init: corrected platform error " "vector %#x setup and enabled\n", cpev);}#endif /* PLATFORM_MCA_HANDLERS */static char *min_state_labels[] = { "nat", "r1", "r2", "r3", "r4", "r5", "r6", "r7", "r8", "r9", "r10","r11", "r12","r13","r14", "r15", "b0r16","b0r17", "b0r18", "b0r19", "b0r20", "b0r21", "b0r22","b0r23", "b0r24", "b0r25", "b0r26", "b0r27", "b0r28","b0r29", "b0r30", "b0r31", "r16", "r17", "r18","r19", "r20", "r21","r22", "r23", "r24","r25", "r26", "r27","r28", "r29", "r30","r31", "preds", "br0", "rsc", "iip", "ipsr", "ifs", "xip", "xpsr", "xfs"};int ia64_pmss_dump_bank0=0; /* dump bank 0 ? *//* * routine to process and prepare to dump min_state_save * information for debugging purposes. * */voidia64_process_min_state_save (pal_min_state_area_t *pmss, struct pt_regs *ptregs){ int i, max=57; u64 *tpmss_ptr=(u64 *)pmss; /* dump out the min_state_area information */ for (i=0;i<max;i++) { if(!ia64_pmss_dump_bank0) { if(strncmp("B0",min_state_labels[i],2)==0) { tpmss_ptr++; /* skip to next entry */ continue; } } printk("%5s=0x%16.16lx ",min_state_labels[i],*tpmss_ptr++); if (((i+1)%3)==0 || ((!strcmp("GR16",min_state_labels[i])) && !ia64_pmss_dump_bank0)) printk("\n"); }}/* * ia64_mca_cmc_vector_setup * * Setup the corrected machine check vector register in the processor and * unmask interrupt. This function is invoked on a per-processor basis. * * Inputs * None * * Outputs * None */voidia64_mca_cmc_vector_setup (void){ cmcv_reg_t cmcv; cmcv.cmcv_regval = 0; cmcv.cmcv_mask = 0; /* Unmask/enable interrupt */ cmcv.cmcv_vector = IA64_CMC_VECTOR; ia64_set_cmcv(cmcv.cmcv_regval); IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d corrected " "machine check vector %#x setup and enabled.\n", smp_processor_id(), IA64_CMC_VECTOR); IA64_MCA_DEBUG("ia64_mca_platform_init: CPU %d CMCV = %#016lx\n", smp_processor_id(), ia64_get_cmcv());}#if defined(MCA_TEST)sal_log_processor_info_t slpi_buf;voidmca_test(void){ slpi_buf.valid.psi_static_struct = 1; slpi_buf.valid.num_cache_check = 1; slpi_buf.valid.num_tlb_check = 1; slpi_buf.valid.num_bus_check = 1; slpi_buf.valid.processor_static_info.minstate = 1; slpi_buf.valid.processor_static_info.br = 1; slpi_buf.valid.processor_static_info.cr = 1; slpi_buf.valid.processor_static_info.ar = 1; slpi_buf.valid.processor_static_info.rr = 1; slpi_buf.valid.processor_static_info.fr = 1; ia64_os_mca_dispatch();}#endif /* #if defined(MCA_TEST) *//* * verify_guid * * Compares a test guid to a target guid and returns result. * * Inputs * test_guid * (ptr to guid to be verified) * target_guid * (ptr to standard guid to be verified against) * * Outputs * 0 (test verifies against target) * non-zero (test guid does not verify) */static intverify_guid (efi_guid_t *test, efi_guid_t *target){ int rc; if ((rc = memcmp((void *)test, (void *)target, sizeof(efi_guid_t)))) { IA64_MCA_DEBUG("ia64_mca_print: invalid guid = " "{ %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " "%#02x, %#02x, %#02x, %#02x, } } \n ", test->data1, test->data2, test->data3, test->data4[0], test->data4[1], test->data4[2], test->data4[3], test->data4[4], test->data4[5], test->data4[6], test->data4[7]); } return rc;}/* * ia64_mca_init * * Do all the system level mca specific initialization. * * 1. Register spinloop and wakeup request interrupt vectors * * 2. Register OS_MCA handler entry point * * 3. Register OS_INIT handler entry point * * 4. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * * Note that this initialization is done very early before some kernel * services are available. * * Inputs : None * * Outputs : None */void __initia64_mca_init(void){ ia64_fptr_t *mon_init_ptr = (ia64_fptr_t *)ia64_monarch_init_handler; ia64_fptr_t *slave_init_ptr = (ia64_fptr_t *)ia64_slave_init_handler; ia64_fptr_t *mca_hldlr_ptr = (ia64_fptr_t *)ia64_os_mca_dispatch; int i; s64 rc; IA64_MCA_DEBUG("ia64_mca_init: begin\n"); /* Clear the Rendez checkin flag for all cpus */ for(i = 0 ; i < NR_CPUS; i++) ia64_mc_info.imi_rendez_checkin[i] = IA64_MCA_RENDEZ_CHECKIN_NOTDONE; /* * Register the rendezvous spinloop and wakeup mechanism with SAL */ /* Register the rendezvous interrupt vector with SAL */ if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_INT, SAL_MC_PARAM_MECHANISM_INT, IA64_MCA_RENDEZ_VECTOR, IA64_MCA_RENDEZ_TIMEOUT, 0))) { printk("ia64_mca_init: Failed to register rendezvous interrupt " "with SAL. rc = %ld\n", rc); return; } /* Register the wakeup interrupt vector with SAL */ if ((rc = ia64_sal_mc_set_params(SAL_MC_PARAM_RENDEZ_WAKEUP, SAL_MC_PARAM_MECHANISM_INT, IA64_MCA_WAKEUP_VECTOR, 0, 0))) { printk("ia64_mca_init: Failed to register wakeup interrupt with SAL. rc = %ld\n", rc); return; } IA64_MCA_DEBUG("ia64_mca_init: registered mca rendezvous spinloop and wakeup mech.\n"); ia64_mc_info.imi_mca_handler = __pa(mca_hldlr_ptr->fp); /* * XXX - disable SAL checksum by setting size to 0; should be * __pa(ia64_os_mca_dispatch_end) - __pa(ia64_os_mca_dispatch); */ ia64_mc_info.imi_mca_handler_size = 0; /* Register the os mca handler with SAL */ if ((rc = ia64_sal_set_vectors(SAL_VECTOR_OS_MCA, ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp, ia64_mc_info.imi_mca_handler_size, 0, 0, 0))) { printk("ia64_mca_init: Failed to register os mca handler with SAL. rc = %ld\n", rc); return; } IA64_MCA_DEBUG("ia64_mca_init: registered os mca handler with SAL at 0x%lx, gp = 0x%lx\n", ia64_mc_info.imi_mca_handler, mca_hldlr_ptr->gp); /* * XXX - disable SAL checksum by setting size to 0, should be * IA64_INIT_HANDLER_SIZE */ ia64_mc_info.imi_monarch_init_handler = __pa(mon_init_ptr->fp); ia64_mc_info.imi_monarch_init_handler_size = 0; ia64_mc_info.imi_slave_init_handler = __pa(slave_init_ptr->fp); ia64_mc_info.imi_slave_init_handler_size = 0; IA64_MCA_DEBUG("ia64_mca_init: os init handler at %lx\n", ia64_mc_info.imi_monarch_init_handler); /* Register the os init handler with SAL */ if ((rc = 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))) { printk("ia64_mca_init: Failed to register m/s init handlers with SAL. rc = %ld\n", rc); return; } IA64_MCA_DEBUG("ia64_mca_init: registered os init handler with SAL\n"); /* * Configure the CMCI vector and handler. Interrupts for CMC are * per-processor, so AP CMC interrupts are setup in smp_callin() (smp.c). */ register_percpu_irq(IA64_CMC_VECTOR, &cmci_irqaction); ia64_mca_cmc_vector_setup(); /* Setup vector on BSP & enable */ /* Setup the MCA rendezvous interrupt vector */ register_percpu_irq(IA64_MCA_RENDEZ_VECTOR, &mca_rdzv_irqaction); /* Setup the MCA wakeup interrupt vector */ register_percpu_irq(IA64_MCA_WAKEUP_VECTOR, &mca_wkup_irqaction);
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -