diff --git a/[refs] b/[refs] index 6c5c86642bc9..1e38540af896 100644 --- a/[refs] +++ b/[refs] @@ -1,2 +1,2 @@ --- -refs/heads/master: f1f652447694f92beff8a534d94b36ea441c939a +refs/heads/master: e57dbaf77f372ac461b5b0b353c65efae9739a00 diff --git a/trunk/arch/x86/Kconfig b/trunk/arch/x86/Kconfig index 8ec3a1aa4abd..3d2d2ef0e16a 100644 --- a/trunk/arch/x86/Kconfig +++ b/trunk/arch/x86/Kconfig @@ -871,6 +871,7 @@ config X86_REROUTE_FOR_BROKEN_BOOT_IRQS config X86_MCE bool "Machine Check / overheating reporting" + default y ---help--- Machine Check support allows the processor to notify the kernel if it detects a problem (e.g. overheating, data corruption). diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce-inject.c b/trunk/arch/x86/kernel/cpu/mcheck/mce-inject.c index ddc72f839332..fc4beb393577 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce-inject.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce-inject.c @@ -78,7 +78,6 @@ static void raise_exception(struct mce *m, struct pt_regs *pregs) } static cpumask_var_t mce_inject_cpumask; -static DEFINE_MUTEX(mce_inject_mutex); static int mce_raise_notify(unsigned int cmd, struct pt_regs *regs) { @@ -195,11 +194,7 @@ static void raise_mce(struct mce *m) put_online_cpus(); } else #endif - { - preempt_disable(); raise_local(); - preempt_enable(); - } } /* Error injection interface */ @@ -230,10 +225,7 @@ static ssize_t mce_write(struct file *filp, const char __user *ubuf, * so do it a jiffie or two later everywhere. */ schedule_timeout(2); - - mutex_lock(&mce_inject_mutex); raise_mce(&m); - mutex_unlock(&mce_inject_mutex); return usize; } diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce-internal.h b/trunk/arch/x86/kernel/cpu/mcheck/mce-internal.h index 6a05c1d327a9..ed44c8a65858 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce-internal.h +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce-internal.h @@ -28,18 +28,6 @@ extern int mce_ser; extern struct mce_bank *mce_banks; -#ifdef CONFIG_X86_MCE_INTEL -unsigned long mce_intel_adjust_timer(unsigned long interval); -void mce_intel_cmci_poll(void); -void mce_intel_hcpu_update(unsigned long cpu); -#else -# define mce_intel_adjust_timer mce_adjust_timer_default -static inline void mce_intel_cmci_poll(void) { } -static inline void mce_intel_hcpu_update(unsigned long cpu) { } -#endif - -void mce_timer_kick(unsigned long interval); - #ifdef CONFIG_ACPI_APEI int apei_write_mce(struct mce *m); ssize_t apei_read_mce(struct mce *m, u64 *record_id); diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce.c b/trunk/arch/x86/kernel/cpu/mcheck/mce.c index c311122ea838..292d0258311c 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce.c @@ -1266,14 +1266,6 @@ static unsigned long check_interval = 5 * 60; /* 5 minutes */ static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */ static DEFINE_PER_CPU(struct timer_list, mce_timer); -static unsigned long mce_adjust_timer_default(unsigned long interval) -{ - return interval; -} - -static unsigned long (*mce_adjust_timer)(unsigned long interval) = - mce_adjust_timer_default; - static void mce_timer_fn(unsigned long data) { struct timer_list *t = &__get_cpu_var(mce_timer); @@ -1284,7 +1276,6 @@ static void mce_timer_fn(unsigned long data) if (mce_available(__this_cpu_ptr(&cpu_info))) { machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_poll_banks)); - mce_intel_cmci_poll(); } /* @@ -1292,38 +1283,14 @@ static void mce_timer_fn(unsigned long data) * polling interval, otherwise increase the polling interval. */ iv = __this_cpu_read(mce_next_interval); - if (mce_notify_irq()) { + if (mce_notify_irq()) iv = max(iv / 2, (unsigned long) HZ/100); - } else { + else iv = min(iv * 2, round_jiffies_relative(check_interval * HZ)); - iv = mce_adjust_timer(iv); - } __this_cpu_write(mce_next_interval, iv); - /* Might have become 0 after CMCI storm subsided */ - if (iv) { - t->expires = jiffies + iv; - add_timer_on(t, smp_processor_id()); - } -} -/* - * Ensure that the timer is firing in @interval from now. - */ -void mce_timer_kick(unsigned long interval) -{ - struct timer_list *t = &__get_cpu_var(mce_timer); - unsigned long when = jiffies + interval; - unsigned long iv = __this_cpu_read(mce_next_interval); - - if (timer_pending(t)) { - if (time_before(when, t->expires)) - mod_timer_pinned(t, when); - } else { - t->expires = round_jiffies(when); - add_timer_on(t, smp_processor_id()); - } - if (interval < iv) - __this_cpu_write(mce_next_interval, interval); + t->expires = jiffies + iv; + add_timer_on(t, smp_processor_id()); } /* Must not be called in IRQ context where del_timer_sync() can deadlock */ @@ -1618,7 +1585,6 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) switch (c->x86_vendor) { case X86_VENDOR_INTEL: mce_intel_feature_init(c); - mce_adjust_timer = mce_intel_adjust_timer; break; case X86_VENDOR_AMD: mce_amd_feature_init(c); @@ -1628,28 +1594,23 @@ static void __mcheck_cpu_init_vendor(struct cpuinfo_x86 *c) } } -static void mce_start_timer(unsigned int cpu, struct timer_list *t) +static void __mcheck_cpu_init_timer(void) { - unsigned long iv = mce_adjust_timer(check_interval * HZ); + struct timer_list *t = &__get_cpu_var(mce_timer); + unsigned long iv = check_interval * HZ; - __this_cpu_write(mce_next_interval, iv); + setup_timer(t, mce_timer_fn, smp_processor_id()); - if (mce_ignore_ce || !iv) + if (mce_ignore_ce) return; + __this_cpu_write(mce_next_interval, iv); + if (!iv) + return; t->expires = round_jiffies(jiffies + iv); add_timer_on(t, smp_processor_id()); } -static void __mcheck_cpu_init_timer(void) -{ - struct timer_list *t = &__get_cpu_var(mce_timer); - unsigned int cpu = smp_processor_id(); - - setup_timer(t, mce_timer_fn, cpu); - mce_start_timer(cpu, t); -} - /* Handle unconfigured int18 (should never happen) */ static void unexpected_machine_check(struct pt_regs *regs, long error_code) { @@ -2333,33 +2294,38 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu) unsigned int cpu = (unsigned long)hcpu; struct timer_list *t = &per_cpu(mce_timer, cpu); - switch (action & ~CPU_TASKS_FROZEN) { + switch (action) { case CPU_ONLINE: + case CPU_ONLINE_FROZEN: mce_device_create(cpu); if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); break; case CPU_DEAD: + case CPU_DEAD_FROZEN: if (threshold_cpu_callback) threshold_cpu_callback(action, cpu); mce_device_remove(cpu); - mce_intel_hcpu_update(cpu); break; case CPU_DOWN_PREPARE: - smp_call_function_single(cpu, mce_disable_cpu, &action, 1); + case CPU_DOWN_PREPARE_FROZEN: del_timer_sync(t); + smp_call_function_single(cpu, mce_disable_cpu, &action, 1); break; case CPU_DOWN_FAILED: + case CPU_DOWN_FAILED_FROZEN: + if (!mce_ignore_ce && check_interval) { + t->expires = round_jiffies(jiffies + + per_cpu(mce_next_interval, cpu)); + add_timer_on(t, cpu); + } smp_call_function_single(cpu, mce_reenable_cpu, &action, 1); - mce_start_timer(cpu, t); break; - } - - if (action == CPU_POST_DEAD) { + case CPU_POST_DEAD: /* intentionally ignoring frozen here */ cmci_rediscover(cpu); + break; } - return NOTIFY_OK; } diff --git a/trunk/arch/x86/kernel/cpu/mcheck/mce_intel.c b/trunk/arch/x86/kernel/cpu/mcheck/mce_intel.c index 098386fed48e..38e49bc95ffc 100644 --- a/trunk/arch/x86/kernel/cpu/mcheck/mce_intel.c +++ b/trunk/arch/x86/kernel/cpu/mcheck/mce_intel.c @@ -15,8 +15,6 @@ #include #include -#include "mce-internal.h" - /* * Support for Intel Correct Machine Check Interrupts. This allows * the CPU to raise an interrupt when a corrected machine check happened. @@ -32,22 +30,7 @@ static DEFINE_PER_CPU(mce_banks_t, mce_banks_owned); */ static DEFINE_RAW_SPINLOCK(cmci_discover_lock); -#define CMCI_THRESHOLD 1 -#define CMCI_POLL_INTERVAL (30 * HZ) -#define CMCI_STORM_INTERVAL (1 * HZ) -#define CMCI_STORM_THRESHOLD 15 - -static DEFINE_PER_CPU(unsigned long, cmci_time_stamp); -static DEFINE_PER_CPU(unsigned int, cmci_storm_cnt); -static DEFINE_PER_CPU(unsigned int, cmci_storm_state); - -enum { - CMCI_STORM_NONE, - CMCI_STORM_ACTIVE, - CMCI_STORM_SUBSIDED, -}; - -static atomic_t cmci_storm_on_cpus; +#define CMCI_THRESHOLD 1 static int cmci_supported(int *banks) { @@ -70,93 +53,6 @@ static int cmci_supported(int *banks) return !!(cap & MCG_CMCI_P); } -void mce_intel_cmci_poll(void) -{ - if (__this_cpu_read(cmci_storm_state) == CMCI_STORM_NONE) - return; - machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); -} - -void mce_intel_hcpu_update(unsigned long cpu) -{ - if (per_cpu(cmci_storm_state, cpu) == CMCI_STORM_ACTIVE) - atomic_dec(&cmci_storm_on_cpus); - - per_cpu(cmci_storm_state, cpu) = CMCI_STORM_NONE; -} - -unsigned long mce_intel_adjust_timer(unsigned long interval) -{ - int r; - - if (interval < CMCI_POLL_INTERVAL) - return interval; - - switch (__this_cpu_read(cmci_storm_state)) { - case CMCI_STORM_ACTIVE: - /* - * We switch back to interrupt mode once the poll timer has - * silenced itself. That means no events recorded and the - * timer interval is back to our poll interval. - */ - __this_cpu_write(cmci_storm_state, CMCI_STORM_SUBSIDED); - r = atomic_sub_return(1, &cmci_storm_on_cpus); - if (r == 0) - pr_notice("CMCI storm subsided: switching to interrupt mode\n"); - /* FALLTHROUGH */ - - case CMCI_STORM_SUBSIDED: - /* - * We wait for all cpus to go back to SUBSIDED - * state. When that happens we switch back to - * interrupt mode. - */ - if (!atomic_read(&cmci_storm_on_cpus)) { - __this_cpu_write(cmci_storm_state, CMCI_STORM_NONE); - cmci_reenable(); - cmci_recheck(); - } - return CMCI_POLL_INTERVAL; - default: - /* - * We have shiny weather. Let the poll do whatever it - * thinks. - */ - return interval; - } -} - -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_clear(); - __this_cpu_write(cmci_storm_state, CMCI_STORM_ACTIVE); - r = atomic_add_return(1, &cmci_storm_on_cpus); - mce_timer_kick(CMCI_POLL_INTERVAL); - - if (r == 1) - pr_notice("CMCI storm detected: switching to poll mode\n"); - return true; -} - /* * The interrupt handler. This is called on every event. * Just call the poller directly to log any events. @@ -165,21 +61,28 @@ static bool cmci_storm_detect(void) */ static void intel_threshold_interrupt(void) { - if (cmci_storm_detect()) - return; machine_check_poll(MCP_TIMESTAMP, &__get_cpu_var(mce_banks_owned)); mce_notify_irq(); } +static void print_update(char *type, int *hdr, int num) +{ + if (*hdr == 0) + printk(KERN_INFO "CPU %d MCA banks", smp_processor_id()); + *hdr = 1; + printk(KERN_CONT " %s:%d", type, num); +} + /* * Enable CMCI (Corrected Machine Check Interrupt) for available MCE banks * on this CPU. Use the algorithm recommended in the SDM to discover shared * banks. */ -static void cmci_discover(int banks) +static void cmci_discover(int banks, int boot) { unsigned long *owned = (void *)&__get_cpu_var(mce_banks_owned); unsigned long flags; + int hdr = 0; int i; raw_spin_lock_irqsave(&cmci_discover_lock, flags); @@ -193,7 +96,8 @@ static void cmci_discover(int banks) /* Already owned by someone else? */ if (val & MCI_CTL2_CMCI_EN) { - clear_bit(i, owned); + if (test_and_clear_bit(i, owned) && !boot) + print_update("SHD", &hdr, i); __clear_bit(i, __get_cpu_var(mce_poll_banks)); continue; } @@ -205,13 +109,16 @@ static void cmci_discover(int banks) /* Did the enable bit stick? -- the bank supports CMCI */ if (val & MCI_CTL2_CMCI_EN) { - set_bit(i, owned); + if (!test_and_set_bit(i, owned) && !boot) + print_update("CMCI", &hdr, i); __clear_bit(i, __get_cpu_var(mce_poll_banks)); } else { WARN_ON(!test_bit(i, __get_cpu_var(mce_poll_banks))); } } raw_spin_unlock_irqrestore(&cmci_discover_lock, flags); + if (hdr) + printk(KERN_CONT "\n"); } /* @@ -279,7 +186,7 @@ void cmci_rediscover(int dying) continue; /* Recheck banks in case CPUs don't all have the same */ if (cmci_supported(&banks)) - cmci_discover(banks); + cmci_discover(banks, 0); } set_cpus_allowed_ptr(current, old); @@ -293,7 +200,7 @@ void cmci_reenable(void) { int banks; if (cmci_supported(&banks)) - cmci_discover(banks); + cmci_discover(banks, 0); } static void intel_init_cmci(void) @@ -304,7 +211,7 @@ static void intel_init_cmci(void) return; mce_threshold_vector = intel_threshold_interrupt; - cmci_discover(banks); + cmci_discover(banks, 1); /* * For CPU #0 this runs with still disabled APIC, but that's * ok because only the vector is set up. We still do another