vserver 1.9.5.x5
[linux-2.6.git] / arch / x86_64 / kernel / mce.c
index cf1fe8b..86f9fd8 100644 (file)
@@ -31,6 +31,8 @@ static int mce_dont_init;
 static int tolerant = 1;
 static int banks;
 static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
+static unsigned long console_logged;
+static int notify_user;
 
 /*
  * Lockless MCE logging infrastructure.
@@ -43,7 +45,7 @@ struct mce_log mcelog = {
        MCE_LOG_LEN,
 }; 
 
-static void mce_log(struct mce *mce)
+void mce_log(struct mce *mce)
 {
        unsigned next, entry;
        mce->finished = 0;
@@ -68,6 +70,9 @@ static void mce_log(struct mce *mce)
        smp_wmb();
        mcelog.entry[entry].finished = 1;
        smp_wmb();
+
+       if (!test_and_set_bit(0, &console_logged))
+               notify_user = 1;
 }
 
 static void print_mce(struct mce *m)
@@ -191,6 +196,8 @@ void do_machine_check(struct pt_regs * regs, long error_code)
                        panicm = m;
                        panicm_found = 1;
                }
+
+               tainted |= TAINT_MACHINE_CHECK;
        }
 
        /* Never do anything final in the polling timer */
@@ -250,6 +257,19 @@ static void mcheck_timer(void *data)
 {
        on_each_cpu(mcheck_check_cpu, NULL, 1, 1);
        schedule_delayed_work(&mcheck_work, check_interval * HZ);
+
+       /*
+        * It's ok to read stale data here for notify_user and
+        * console_logged as we'll simply get the updated versions
+        * on the next mcheck_timer execution and atomic operations
+        * on console_logged act as synchronization for notify_user
+        * writes.
+        */
+       if (notify_user && console_logged) {
+               notify_user = 0;
+               clear_bit(0, &console_logged);
+               printk(KERN_INFO "Machine check events logged\n");
+       }
 }
 
 
@@ -303,22 +323,34 @@ static void __init mce_cpu_quirks(struct cpuinfo_x86 *c)
        }
 }                      
 
+static void __init mce_cpu_features(struct cpuinfo_x86 *c)
+{
+       switch (c->x86_vendor) {
+       case X86_VENDOR_INTEL:
+               mce_intel_feature_init(c);
+               break;
+       default:
+               break;
+       }
+}
+
 /* 
  * Called for each booted CPU to set up machine checks.
  * Must be called with preempt off. 
  */
 void __init mcheck_init(struct cpuinfo_x86 *c)
 {
-       static unsigned long mce_cpus __initdata = 0;
+       static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
 
        mce_cpu_quirks(c); 
 
        if (mce_dont_init ||
-           test_and_set_bit(smp_processor_id(), &mce_cpus) ||
+           cpu_test_and_set(smp_processor_id(), mce_cpus) ||
            !mce_available(c))
                return;
 
        mce_init(NULL);
+       mce_cpu_features(c);
 }
 
 /*
@@ -359,8 +391,7 @@ static ssize_t mce_read(struct file *filp, char __user *ubuf, size_t usize, loff
 
        memset(mcelog.entry, 0, next * sizeof(struct mce));
        mcelog.next = 0;
-       smp_wmb(); 
-       
+
        synchronize_kernel();   
 
        /* Collect entries that were still getting written before the synchronize. */