📄 mca.c
字号:
/* * File: mca.c * Purpose: Generic MCA handling layer * * Updated for latest kernel * 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) * * 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/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> typedef 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[256];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_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);extern void ia64_monarch_init_handler (void);extern void ia64_slave_init_handler (void);/* * hack for now, add platform dependent handlers * here */#ifndef PLATFORM_MCA_HANDLERSvoidmca_handler_platform (void){}voidcmci_handler_platform (int cmc_irq, void *arg, struct pt_regs *ptregs){}/* * 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 */}voidlog_print_platform ( void *cur_buff_ptr, prfunc_t prfunc){} voidia64_mca_init_platform (void){}#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"); } /* hang city for now, until we include debugger or copy to ptregs to show: */ while (1);} /* * 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 voidia64_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;voidmca_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) *//* * ia64_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 ia64_mca_init. * * 5. Initialize MCA/CMC/INIT related log buffers maintained by the OS. * * 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; int i; IA64_MCA_DEBUG("ia64_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; IA64_MCA_DEBUG("ia64_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); IA64_MCA_DEBUG("ia64_mca_init : correctable mca vector setup done\n"); ia64_mc_info.imi_mca_handler = __pa(ia64_os_mca_dispatch); /* * 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 (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; IA64_MCA_DEBUG("ia64_mca_init : registered os mca handler with SAL\n"); /* * 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 (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; IA64_MCA_DEBUG("ia64_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); ia64_mca_init_platform(); IA64_MCA_DEBUG("ia64_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 */voidia64_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 */voidia64_mca_wakeup(int cpu){ platform_send_ipi(cpu, IA64_MCA_WAKEUP_INT_VECTOR, IA64_IPI_DM_INT, 0); 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 */voidia64_mca_wakeup_all(void){ int cpu; /* Clear the Rendez checkin flag for all cpus */ for(cpu = 0 ; cpu < smp_num_cpus; 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 */voidia64_mca_rendez_int_handler(int rendez_irq, void *arg, struct pt_regs *ptregs){ int flags, cpu = 0; /* Mask all interrupts */ save_and_cli(flags);#ifdef CONFIG_SMP cpu = cpu_logical_id(hard_smp_processor_id());#endif ia64_mc_info.imi_rendez_checkin[cpu] = 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 * */voidia64_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 */voidia64_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
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -