📄 mca.c
字号:
/* Setup the CPE interrupt vector */ { irq_desc_t *desc; unsigned int irq; int cpev = acpi_request_vector(ACPI20_ENTRY_PIS_CPEI); if (cpev >= 0) { for (irq = 0; irq < NR_IRQS; ++irq) if (irq_to_vector(irq) == cpev) { desc = irq_desc(irq); desc->status |= IRQ_PER_CPU; desc->handler = &irq_type_iosapic_level; setup_irq(irq, &mca_cpe_irqaction); } ia64_mca_register_cpev(cpev); } else printk("ia64_mca_init: Failed to get routed CPEI vector from ACPI.\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); ia64_log_init(SAL_INFO_TYPE_INIT); ia64_log_init(SAL_INFO_TYPE_CMC); ia64_log_init(SAL_INFO_TYPE_CPE);#if defined(MCA_TEST) mca_test();#endif /* #if defined(MCA_TEST) */ printk("Mca related initialization done\n");#if 0 // Too early in initialization -- error log is lost /* Do post-failure MCA error logging */ ia64_mca_check_errors();#endif // Too early in initialization -- error log is lost}/* * 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_VECTOR >> 6); int irr_bit = (IA64_MCA_WAKEUP_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_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 : None * */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; /* Cold Boot for uncorrectable MCA */ ia64_os_to_sal_handoff_state.imots_os_status = IA64_MCA_COLD_BOOT;}/* * 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 rendezvous spinloop. * * Inputs : None * Outputs : None */voidia64_mca_ucmc_handler(void){#if 0 /* stubbed out @FVL */ /* * Attempting to log a DBE error Causes "reserved register/field panic" * in printk. */ /* Get the MCA error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_MCA);#endif /* stubbed out @FVL */ /* * Do Platform-specific mca error handling if required. */ mca_handler_platform() ; /* * Wakeup all the processors which are spinning in the rendezvous * loop. */ ia64_mca_wakeup_all(); /* Return to SAL */ ia64_return_to_sal_check();}/* * ia64_mca_cmc_int_handler * * This is corrected machine check interrupt handler. * Right now the logs are extracted and displayed in a well-defined * format. * * Inputs * interrupt number * client data arg ptr * saved registers ptr * * Outputs * None */voidia64_mca_cmc_int_handler(int cmc_irq, void *arg, struct pt_regs *ptregs){ IA64_MCA_DEBUG("ia64_mca_cmc_int_handler: received interrupt vector = %#x on CPU %d\n", cmc_irq, smp_processor_id()); /* Get the CMC error record and log it */ ia64_mca_log_sal_error_record(SAL_INFO_TYPE_CMC);}/* * IA64_MCA log support */#define IA64_MAX_LOGS 2 /* Double-buffering for nested MCAs */#define IA64_MAX_LOG_TYPES 4 /* MCA, INIT, CMC, CPE */typedef struct ia64_state_log_s{ spinlock_t isl_lock; int isl_index; ia64_err_rec_t isl_log[IA64_MAX_LOGS]; /* need space to store header + error log */} ia64_state_log_t;static ia64_state_log_t ia64_state_log[IA64_MAX_LOG_TYPES];/* Note: Some of these macros assume IA64_MAX_LOGS is always 2. Should be *//* fixed. @FVL */#define IA64_LOG_LOCK_INIT(it) spin_lock_init(&ia64_state_log[it].isl_lock)#define IA64_LOG_LOCK(it) spin_lock_irqsave(&ia64_state_log[it].isl_lock, s)#define IA64_LOG_UNLOCK(it) spin_unlock_irqrestore(&ia64_state_log[it].isl_lock,s)#define IA64_LOG_NEXT_INDEX(it) ia64_state_log[it].isl_index#define IA64_LOG_CURR_INDEX(it) 1 - ia64_state_log[it].isl_index#define IA64_LOG_INDEX_INC(it) \ ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index#define IA64_LOG_INDEX_DEC(it) \ ia64_state_log[it].isl_index = 1 - ia64_state_log[it].isl_index#define IA64_LOG_NEXT_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_NEXT_INDEX(it)]))#define IA64_LOG_CURR_BUFFER(it) (void *)(&(ia64_state_log[it].isl_log[IA64_LOG_CURR_INDEX(it)]))/* * C portion of the OS INIT handler * * Called from ia64_<monarch/slave>_init_handler * * Inputs: pointer to pt_regs where processor info was saved. * * Returns: * 0 if SAL must warm boot the System * 1 if SAL must return to interrupted context using PAL_MC_RESUME * */voidia64_init_handler (struct pt_regs *regs){ sal_log_processor_info_t *proc_ptr; ia64_err_rec_t *plog_ptr; printk("Entered OS INIT handler\n"); /* Get the INIT processor log */ if (!ia64_log_get(SAL_INFO_TYPE_INIT, (prfunc_t)printk)) return; // no record retrieved#ifdef IA64_DUMP_ALL_PROC_INFO ia64_log_print(SAL_INFO_TYPE_INIT, (prfunc_t)printk);#endif /* * get pointer to min state save area * */ plog_ptr=(ia64_err_rec_t *)IA64_LOG_CURR_BUFFER(SAL_INFO_TYPE_INIT); proc_ptr = &plog_ptr->proc_err; ia64_process_min_state_save(&proc_ptr->processor_static_info.min_state_area, regs); /* Clear the INIT SAL logs now that they have been saved in the OS buffer */ ia64_sal_clear_state_info(SAL_INFO_TYPE_INIT); init_handler_platform(regs); /* call platform specific routines */}/* * ia64_log_prt_guid * * Print a formatted GUID. * * Inputs : p_guid (ptr to the GUID) * prfunc (print function) * Outputs : None * */voidia64_log_prt_guid (efi_guid_t *p_guid, prfunc_t prfunc){ printk("GUID = { %08x, %04x, %04x, { %#02x, %#02x, %#02x, %#02x, " "%#02x, %#02x, %#02x, %#02x, } } \n ", p_guid->data1, p_guid->data2, p_guid->data3, p_guid->data4[0], p_guid->data4[1], p_guid->data4[2], p_guid->data4[3], p_guid->data4[4], p_guid->data4[5], p_guid->data4[6], p_guid->data4[7]);}static voidia64_log_hexdump(unsigned char *p, unsigned long n_ch, prfunc_t prfunc){ int i, j; if (!p) return; for (i = 0; i < n_ch;) { prfunc("%p ", (void *)p); for (j = 0; (j < 16) && (i < n_ch); i++, j++, p++) { prfunc("%02x ", *p); } prfunc("\n"); }}#ifdef MCA_PRT_XTRA_DATA // for test only @FVLstatic voidia64_log_prt_record_header (sal_log_record_header_t *rh, prfunc_t prfunc){ prfunc("SAL RECORD HEADER: Record buffer = %p, header size = %ld\n", (void *)rh, sizeof(sal_log_record_header_t)); ia64_log_hexdump((unsigned char *)rh, sizeof(sal_log_record_header_t), (prfunc_t)prfunc); prfunc("Total record length = %d\n", rh->len); ia64_log_prt_guid(&rh->platform_guid, prfunc); prfunc("End of SAL RECORD HEADER\n");}static voidia64_log_prt_section_header (sal_log_section_hdr_t *sh, prfunc_t prfunc){ prfunc("SAL SECTION HEADER: Record buffer = %p, header size = %ld\n", (void *)sh, sizeof(sal_log_section_hdr_t)); ia64_log_hexdump((unsigned char *)sh, sizeof(sal_log_section_hdr_t), (prfunc_t)prfunc); prfunc("Length of section & header = %d\n", sh->len); ia64_log_prt_guid(&sh->guid, prfunc); prfunc("End of SAL SECTION HEADER\n");}#endif // MCA_PRT_XTRA_DATA for test only @FVL/* * ia64_log_init * Reset the OS ia64 log buffer * Inputs : info_type (SAL_INFO_TYPE_{MCA,INIT,CMC,CPE}) * Outputs : None */voidia64_log_init(int sal_info_type){ IA64_LOG_LOCK_INIT(sal_info_type); IA64_LOG_NEXT_INDEX(sal_info_type) = 0; memset(IA64_LOG_NEXT_BUFFER(sal_info_type), 0, sizeof(ia64_err_rec_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,CPE}) * prfunc (fn ptr of log output function) * Outputs : size (total record length) * */u64ia64_log_get(int sal_info_type, prfunc_t prfunc){ sal_log_record_header_t *log_buffer; u64 total_len = 0; int s; IA64_LOG_LOCK(sal_info_type); /* Get the process state information */ log_buffer = IA64_LOG_NEXT_BUFFER(sal_info_type); total_len = ia64_sal_get_state_info(sal_info_type, (u64 *)log_buffer); if (total_len) { IA64_LOG_INDEX_INC(sal_info_type); IA64_LOG_UNLOCK(sal_info_type); IA64_MCA_DEBUG("ia64_log_get: SAL error record type %d retrieved. " "Record length = %ld\n", sal_info_type, total_len); return total_len; } else { IA64_LOG_UNLOCK(sal_info_type); prfunc("ia64_log_get: Failed to retrieve SAL error record type %d\n", sal_info_type); return 0; }}/* * ia64_log_prt_oem_data * * Print OEM specific data if included. * * Inputs : header_len (length passed in section header) * sect_len (default length of section type) * p_data (ptr to data) * prfunc (print function) * Outputs : None *
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -