x86/MCE: Save microcode revision in machine check records
[pandora-kernel.git] / arch / x86 / kernel / cpu / mcheck / mce.c
index 2af127d..1f439d4 100644 (file)
@@ -52,6 +52,9 @@ static DEFINE_MUTEX(mce_chrdev_read_mutex);
                              rcu_read_lock_sched_held() || \
                              lockdep_is_held(&mce_chrdev_read_mutex))
 
+/* sysfs synchronization */
+static DEFINE_MUTEX(mce_sysfs_mutex);
+
 #define CREATE_TRACE_POINTS
 #include <trace/events/mce.h>
 
@@ -119,11 +122,11 @@ void mce_setup(struct mce *m)
        m->time = get_seconds();
        m->cpuvendor = boot_cpu_data.x86_vendor;
        m->cpuid = cpuid_eax(1);
-#ifdef CONFIG_SMP
        m->socketid = cpu_data(m->extcpu).phys_proc_id;
-#endif
        m->apicid = cpu_data(m->extcpu).initial_apicid;
        rdmsrl(MSR_IA32_MCG_CAP, m->mcgcap);
+
+       m->microcode = boot_cpu_data.microcode;
 }
 
 DEFINE_PER_CPU(struct mce, injectm);
@@ -220,7 +223,7 @@ static void print_mce(struct mce *m)
         */
        pr_emerg(HW_ERR "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x microcode %x\n",
                m->cpuvendor, m->cpuid, m->time, m->socketid, m->apicid,
-               cpu_data(m->extcpu).microcode);
+               m->microcode);
 
        /*
         * Print out human-readable details about the MCE error,
@@ -389,6 +392,14 @@ static inline void mce_gather_info(struct mce *m, struct pt_regs *regs)
                if (m->mcgstatus & (MCG_STATUS_RIPV|MCG_STATUS_EIPV)) {
                        m->ip = regs->ip;
                        m->cs = regs->cs;
+
+                       /*
+                        * When in VM86 mode make the cs look like ring 3
+                        * always. This is a lie, but it's better than passing
+                        * the additional vm86 bit around everywhere.
+                        */
+                       if (v8086_mode(regs))
+                               m->cs |= 3;
                }
                /* Use accurate RIP reporting if available. */
                if (rip_msr)
@@ -1401,6 +1412,11 @@ static void unexpected_machine_check(struct pt_regs *regs, long error_code)
 void (*machine_check_vector)(struct pt_regs *, long error_code) =
                                                unexpected_machine_check;
 
+void do_mce(struct pt_regs *regs, long error_code)
+{
+       machine_check_vector(regs, error_code);
+}
+
 /*
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off:
@@ -1872,6 +1888,7 @@ static ssize_t set_ignore_ce(struct sys_device *s,
        if (strict_strtoull(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mce_ignore_ce ^ !!new) {
                if (new) {
                        /* disable ce features */
@@ -1884,6 +1901,8 @@ static ssize_t set_ignore_ce(struct sys_device *s,
                        on_each_cpu(mce_enable_ce, (void *)1, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -1896,6 +1915,7 @@ static ssize_t set_cmci_disabled(struct sys_device *s,
        if (strict_strtoull(buf, 0, &new) < 0)
                return -EINVAL;
 
+       mutex_lock(&mce_sysfs_mutex);
        if (mce_cmci_disabled ^ !!new) {
                if (new) {
                        /* disable cmci */
@@ -1907,6 +1927,8 @@ static ssize_t set_cmci_disabled(struct sys_device *s,
                        on_each_cpu(mce_enable_ce, NULL, 1);
                }
        }
+       mutex_unlock(&mce_sysfs_mutex);
+
        return size;
 }
 
@@ -1914,8 +1936,19 @@ static ssize_t store_int_with_restart(struct sys_device *s,
                                      struct sysdev_attribute *attr,
                                      const char *buf, size_t size)
 {
-       ssize_t ret = sysdev_store_int(s, attr, buf, size);
+       unsigned long old_check_interval = check_interval;
+       ssize_t ret = sysdev_store_ulong(s, attr, buf, size);
+
+       if (check_interval == old_check_interval)
+               return ret;
+
+       if (check_interval < 1)
+               check_interval = 1;
+
+       mutex_lock(&mce_sysfs_mutex);
        mce_restart();
+       mutex_unlock(&mce_sysfs_mutex);
+
        return ret;
 }