C++ arch/x86/kernel/cpu/mce/intel.c void intel_init_cmci(void) { int banks; if (!cmci_supported(&banks)) return; mce_threshold_vector = intel_threshold_interrupt; cmci_discover(banks); /* * For CPU #0 this runs with still disabled APIC, but that's * ok because only the vector is set up. We still do another * check for the banks later for CPU #0 just to make sure * to not miss any events. */ apic_write(APIC_LVTCMCI, THRESHOLD_APIC_VECTOR|APIC_DM_FIXED); cmci_recheck(); } |
C++ rdmsrl(MSR_IA32_MCx_CTL2(i), val); ... val |= MCI_CTL2_CMCI_EN; wrmsrl(MSR_IA32_MCx_CTL2(i), val); rdmsrl(MSR_IA32_MCx_CTL2(i), val); |
C++ #define CMCI_THRESHOLD 1 if (!mca_cfg.bios_cmci_threshold) { val &= ~MCI_CTL2_CMCI_THRESHOLD_MASK; val |= CMCI_THRESHOLD; } else if (!(val & MCI_CTL2_CMCI_THRESHOLD_MASK)) { /* * If bios_cmci_threshold boot option was specified * but the threshold is zero, we'll try to initialize * it to 1. */ bios_zero_thresh = 1; val |= CMCI_THRESHOLD; } |
C++ /* * The interrupt handler. This is called on every event. * Just call the poller directly to log any events. * This could in theory increase the threshold under high load, * but doesn't for now. */ static void intel_threshold_interrupt(void) { if (cmci_storm_detect()) return; machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_banks_owned)); } |
C++ static bool cmci_storm_detect(void) { unsigned int cnt = __this_cpu_read(cmci_storm_cnt); unsigned long ts = __this_cpu_read(cmci_time_stamp); unsigned long now = jiffies; int r; if (__this_cpu_read(cmci_storm_state) != CMCI_STORM_NONE) return true; if (time_before_eq(now, ts + CMCI_STORM_INTERVAL)) { cnt++; } else { cnt = 1; __this_cpu_write(cmci_time_stamp, now); } __this_cpu_write(cmci_storm_cnt, cnt); if (cnt <= CMCI_STORM_THRESHOLD) return false; cmci_toggle_interrupt_mode(false); __this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE); r = atomic_add_return(1, &cmci_storm_on_cpus); mce_timer_kick(CMCI_STORM_INTERVAL); this_cpu_write(cmci_backoff_cnt, INITIAL_CHECK_INTERVAL); if (r == 1) pr_notice("CMCI storm detected: switching to poll mode\n"); return true; } |
C++ enum mcp_flags { MCP_TIMESTAMP = BIT(0), /* log time stamp */ MCP_UC = BIT(1), /* log uncorrected errors */ MCP_DONTLOG = BIT(2), /* only clear, don't log */ }; |
C++ bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b) { if (flags & MCP_TIMESTAMP) m.tsc = rdtsc(); // 记录当前TSC /*CE Error记录*/ /* If this entry is not valid, ignore it */ if (!(m.status & MCI_STATUS_VAL)) continue; /* * If we are logging everything (at CPU online) or this * is a corrected error, then we must log it. */ if ((flags & MCP_UC) || !(m.status & MCI_STATUS_UC)) goto log_it; /*UCNA Error记录*/ /* * Log UCNA (SDM: 15.6.3 "UCR Error Classification") * UC == 1 && PCC == 0 && S == 0 */ if (!(m.status & MCI_STATUS_PCC) && !(m.status & MCI_STATUS_S)) goto log_it; /*通过mce_log记录故障信息*/ log_it: /* * Don't get the IP here because it's unlikely to * have anything to do with the actual error location. */ if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce) mce_log(&m); else if (mce_usable_address(&m)) { /* * Although we skipped logging this, we still want * to take action. Add to the pool so the registered * notifiers will see it. */ if (!mce_gen_pool_add(&m)) mce_schedule_work(); } } |
欢迎光临 谷动谷力 (http://bbs.sunsili.com/) | Powered by Discuz! X3.2 |