Merge branch 'x86-ras-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
authorLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 20:33:20 +0000 (13:33 -0700)
committerLinus Torvalds <torvalds@linux-foundation.org>
Mon, 13 Apr 2015 20:33:20 +0000 (13:33 -0700)
Pull x86 RAS changes from Ingo Molnar:
 "The main changes in this cycle were:

   - Simplify the CMCI storm logic on Intel CPUs after yet another
     report about a race in the code (Borislav Petkov)

   - Enable the MCE threshold irq on AMD CPUs by default (Aravind
     Gopalakrishnan)

   - Add AMD-specific MCE-severity grading function.  Further error
     recovery actions will be based on its output (Aravind Gopalakrishnan)

   - Documentation updates (Borislav Petkov)

   - ... assorted fixes and cleanups"

* 'x86-ras-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/tip/tip:
  x86/mce/severity: Fix warning about indented braces
  x86/mce: Define mce_severity function pointer
  x86/mce: Add an AMD severities-grading function
  x86/mce: Reindent __mcheck_cpu_apply_quirks() properly
  x86/mce: Use safe MSR accesses for AMD quirk
  x86/MCE/AMD: Enable thresholding interrupts by default if supported
  x86/MCE: Make mce_panic() fatal machine check msg in the same pattern
  x86/MCE/intel: Cleanup CMCI storm logic
  Documentation/acpi/einj: Correct and streamline text
  x86/MCE/AMD: Drop bogus const modifier from AMD's bank4_names()

1  2 
arch/x86/kernel/cpu/mcheck/mce.c

@@@ -44,7 -44,6 +44,7 @@@
  
  #include <asm/processor.h>
  #include <asm/traps.h>
 +#include <asm/tlbflush.h>
  #include <asm/mce.h>
  #include <asm/msr.h>
  
@@@ -60,11 -59,12 +60,12 @@@ static DEFINE_MUTEX(mce_chrdev_read_mut
  #define CREATE_TRACE_POINTS
  #include <trace/events/mce.h>
  
- #define SPINUNIT 100  /* 100ns */
+ #define SPINUNIT              100     /* 100ns */
  
  DEFINE_PER_CPU(unsigned, mce_exception_count);
  
  struct mce_bank *mce_banks __read_mostly;
+ struct mce_vendor_flags mce_flags __read_mostly;
  
  struct mca_config mca_cfg __read_mostly = {
        .bootlog  = -1,
@@@ -89,9 -89,6 +90,6 @@@ static DECLARE_WAIT_QUEUE_HEAD(mce_chrd
  static DEFINE_PER_CPU(struct mce, mces_seen);
  static int                    cpu_missing;
  
- /* CMCI storm detection filter */
- static DEFINE_PER_CPU(unsigned long, mce_polled_error);
  /*
   * MCA banks polled by the period polling timer for corrected events.
   * With Intel CMCI, this only has MCA banks which do not support CMCI (if any).
@@@ -152,11 -149,14 +150,11 @@@ static struct mce_log mcelog = 
  void mce_log(struct mce *mce)
  {
        unsigned next, entry;
 -      int ret = 0;
  
        /* Emit the trace record: */
        trace_mce_record(mce);
  
 -      ret = atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
 -      if (ret == NOTIFY_STOP)
 -              return;
 +      atomic_notifier_call_chain(&x86_mce_decoder_chain, 0, mce);
  
        mce->finished = 0;
        wmb();
@@@ -622,8 -622,9 +620,9 @@@ DEFINE_PER_CPU(unsigned, mce_poll_count
   * is already totally * confused. In this case it's likely it will
   * not fully execute the machine check handler either.
   */
void machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
bool machine_check_poll(enum mcp_flags flags, mce_banks_t *b)
  {
+       bool error_logged = false;
        struct mce m;
        int severity;
        int i;
                if (!(m.status & MCI_STATUS_VAL))
                        continue;
  
-               this_cpu_write(mce_polled_error, 1);
                /*
                 * Uncorrected or signalled events are handled by the exception
                 * handler when it is enabled, so don't process those here.
                 * 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)
+               if (!(flags & MCP_DONTLOG) && !mca_cfg.dont_log_ce) {
+                       error_logged = true;
                        mce_log(&m);
+               }
  
                /*
                 * Clear state for this bank.
         */
  
        sync_core();
+       return error_logged;
  }
  EXPORT_SYMBOL_GPL(machine_check_poll);
  
@@@ -813,7 -818,7 +816,7 @@@ static void mce_reign(void
         * other CPUs.
         */
        if (m && global_worst >= MCE_PANIC_SEVERITY && mca_cfg.tolerant < 3)
-               mce_panic("Fatal Machine check", m, msg);
+               mce_panic("Fatal machine check", m, msg);
  
        /*
         * For UC somewhere we let the CPU who detects it handle it.
         * source or one CPU is hung. Panic.
         */
        if (global_worst <= MCE_KEEP_SEVERITY && mca_cfg.tolerant < 3)
-               mce_panic("Machine check from unknown source", NULL, NULL);
+               mce_panic("Fatal machine check from unknown source", NULL, NULL);
  
        /*
         * Now clear all the mces_seen so that they don't reappear on
@@@ -1258,7 -1263,7 +1261,7 @@@ void mce_log_therm_throt_event(__u64 st
   * poller finds an MCE, poll 2x faster.  When the poller finds no more
   * errors, poll 2x slower (up to check_interval seconds).
   */
- static unsigned long check_interval = 5 * 60; /* 5 minutes */
+ static unsigned long check_interval = INITIAL_CHECK_INTERVAL;
  
  static DEFINE_PER_CPU(unsigned long, mce_next_interval); /* in jiffies */
  static DEFINE_PER_CPU(struct timer_list, mce_timer);
@@@ -1268,49 -1273,57 +1271,57 @@@ static unsigned long mce_adjust_timer_d
        return interval;
  }
  
- static unsigned long (*mce_adjust_timer)(unsigned long interval) =
-       mce_adjust_timer_default;
+ static unsigned long (*mce_adjust_timer)(unsigned long interval) = mce_adjust_timer_default;
  
- static int cmc_error_seen(void)
+ static void __restart_timer(struct timer_list *t, unsigned long interval)
  {
-       unsigned long *v = this_cpu_ptr(&mce_polled_error);
+       unsigned long when = jiffies + interval;
+       unsigned long flags;
+       local_irq_save(flags);
  
-       return test_and_clear_bit(0, v);
+       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());
+       }
+       local_irq_restore(flags);
  }
  
  static void mce_timer_fn(unsigned long data)
  {
        struct timer_list *t = this_cpu_ptr(&mce_timer);
+       int cpu = smp_processor_id();
        unsigned long iv;
-       int notify;
  
-       WARN_ON(smp_processor_id() != data);
+       WARN_ON(cpu != data);
+       iv = __this_cpu_read(mce_next_interval);
  
        if (mce_available(this_cpu_ptr(&cpu_info))) {
-               machine_check_poll(MCP_TIMESTAMP,
-                               this_cpu_ptr(&mce_poll_banks));
-               mce_intel_cmci_poll();
+               machine_check_poll(MCP_TIMESTAMP, this_cpu_ptr(&mce_poll_banks));
+               if (mce_intel_cmci_poll()) {
+                       iv = mce_adjust_timer(iv);
+                       goto done;
+               }
        }
  
        /*
-        * Alert userspace if needed.  If we logged an MCE, reduce the
-        * polling interval, otherwise increase the polling interval.
+        * Alert userspace if needed. If we logged an MCE, reduce the polling
+        * interval, otherwise increase the polling interval.
         */
-       iv = __this_cpu_read(mce_next_interval);
-       notify = mce_notify_irq();
-       notify |= cmc_error_seen();
-       if (notify) {
+       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);
-       }
+ done:
        __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());
-       }
+       __restart_timer(t, iv);
  }
  
  /*
  void mce_timer_kick(unsigned long interval)
  {
        struct timer_list *t = this_cpu_ptr(&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());
-       }
+       __restart_timer(t, interval);
        if (interval < iv)
                __this_cpu_write(mce_next_interval, interval);
  }
@@@ -1450,7 -1457,7 +1455,7 @@@ static void __mcheck_cpu_init_generic(v
        bitmap_fill(all_banks, MAX_NR_BANKS);
        machine_check_poll(MCP_UC | m_fl, &all_banks);
  
 -      set_in_cr4(X86_CR4_MCE);
 +      cr4_set_bits(X86_CR4_MCE);
  
        rdmsrl(MSR_IA32_MCG_CAP, cap);
        if (cap & MCG_CTL_P)
@@@ -1525,45 -1532,46 +1530,46 @@@ static int __mcheck_cpu_apply_quirks(st
                 * Various K7s with broken bank 0 around. Always disable
                 * by default.
                 */
-                if (c->x86 == 6 && cfg->banks > 0)
+               if (c->x86 == 6 && cfg->banks > 0)
                        mce_banks[0].ctl = 0;
  
-                /*
-                 * Turn off MC4_MISC thresholding banks on those models since
-                 * they're not supported there.
-                 */
-                if (c->x86 == 0x15 &&
-                    (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
-                        int i;
-                        u64 val, hwcr;
-                        bool need_toggle;
-                        u32 msrs[] = {
+               /*
+                * overflow_recov is supported for F15h Models 00h-0fh
+                * even though we don't have a CPUID bit for it.
+                */
+               if (c->x86 == 0x15 && c->x86_model <= 0xf)
+                       mce_flags.overflow_recov = 1;
+               /*
+                * Turn off MC4_MISC thresholding banks on those models since
+                * they're not supported there.
+                */
+               if (c->x86 == 0x15 &&
+                   (c->x86_model >= 0x10 && c->x86_model <= 0x1f)) {
+                       int i;
+                       u64 hwcr;
+                       bool need_toggle;
+                       u32 msrs[] = {
                                0x00000413, /* MC4_MISC0 */
                                0xc0000408, /* MC4_MISC1 */
-                        };
+                       };
  
-                        rdmsrl(MSR_K7_HWCR, hwcr);
+                       rdmsrl(MSR_K7_HWCR, hwcr);
  
-                        /* McStatusWrEn has to be set */
-                        need_toggle = !(hwcr & BIT(18));
+                       /* McStatusWrEn has to be set */
+                       need_toggle = !(hwcr & BIT(18));
  
-                        if (need_toggle)
-                                wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
+                       if (need_toggle)
+                               wrmsrl(MSR_K7_HWCR, hwcr | BIT(18));
  
-                        for (i = 0; i < ARRAY_SIZE(msrs); i++) {
-                                rdmsrl(msrs[i], val);
+                       /* Clear CntP bit safely */
+                       for (i = 0; i < ARRAY_SIZE(msrs); i++)
+                               msr_clear_bit(msrs[i], 62);
  
-                                /* CntP bit set? */
-                                if (val & BIT_64(62)) {
-                                       val &= ~BIT_64(62);
-                                       wrmsrl(msrs[i], val);
-                                }
-                        }
-                        /* restore old settings */
-                        if (need_toggle)
-                                wrmsrl(MSR_K7_HWCR, hwcr);
-                }
+                       /* restore old settings */
+                       if (need_toggle)
+                               wrmsrl(MSR_K7_HWCR, hwcr);
+               }
        }
  
        if (c->x86_vendor == X86_VENDOR_INTEL) {
@@@ -1629,10 -1637,11 +1635,11 @@@ static void __mcheck_cpu_init_vendor(st
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
                mce_intel_feature_init(c);
-               mce_adjust_timer = mce_intel_adjust_timer;
+               mce_adjust_timer = cmci_intel_adjust_timer;
                break;
        case X86_VENDOR_AMD:
                mce_amd_feature_init(c);
+               mce_flags.overflow_recov = cpuid_ebx(0x80000007) & 0x1;
                break;
        default:
                break;
@@@ -2017,6 -2026,7 +2024,7 @@@ __setup("mce", mcheck_enable)
  int __init mcheck_init(void)
  {
        mcheck_intel_therm_init();
+       mcheck_vendor_init_severity();
  
        return 0;
  }