Merge branch 'x86-mce-for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git...
[linux-2.6.git] / arch / x86 / kernel / cpu / mcheck / mce.c
index 325559d..2f5aab2 100644 (file)
@@ -165,6 +165,11 @@ void mce_log(struct mce *mce)
        set_bit(0, &mce_need_notify);
 }
 
+void __weak decode_mce(struct mce *m)
+{
+       return;
+}
+
 static void print_mce(struct mce *m)
 {
        printk(KERN_EMERG
@@ -176,28 +181,33 @@ static void print_mce(struct mce *m)
                       m->cs, m->ip);
                if (m->cs == __KERNEL_CS)
                        print_symbol("{%s}", m->ip);
-               printk("\n");
+               printk(KERN_CONT "\n");
        }
        printk(KERN_EMERG "TSC %llx ", m->tsc);
        if (m->addr)
-               printk("ADDR %llx ", m->addr);
+               printk(KERN_CONT "ADDR %llx ", m->addr);
        if (m->misc)
-               printk("MISC %llx ", m->misc);
-       printk("\n");
+               printk(KERN_CONT "MISC %llx ", m->misc);
+       printk(KERN_CONT "\n");
        printk(KERN_EMERG "PROCESSOR %u:%x TIME %llu SOCKET %u APIC %x\n",
                        m->cpuvendor, m->cpuid, m->time, m->socketid,
                        m->apicid);
+
+       decode_mce(m);
 }
 
 static void print_mce_head(void)
 {
-       printk(KERN_EMERG "\n" KERN_EMERG "HARDWARE ERROR\n");
+       printk(KERN_EMERG "\nHARDWARE ERROR\n");
 }
 
 static void print_mce_tail(void)
 {
        printk(KERN_EMERG "This is not a software problem!\n"
-              KERN_EMERG "Run through mcelog --ascii to decode and contact your hardware vendor\n");
+#if (!defined(CONFIG_EDAC) || !defined(CONFIG_CPU_SUP_AMD))
+              "Run through mcelog --ascii to decode and contact your hardware vendor\n"
+#endif
+              );
 }
 
 #define PANIC_TIMEOUT 5 /* 5 seconds */
@@ -1085,7 +1095,7 @@ void mce_log_therm_throt_event(__u64 status)
  */
 static int check_interval = 5 * 60; /* 5 minutes */
 
-static DEFINE_PER_CPU(int, next_interval); /* in jiffies */
+static DEFINE_PER_CPU(int, mce_next_interval); /* in jiffies */
 static DEFINE_PER_CPU(struct timer_list, mce_timer);
 
 static void mcheck_timer(unsigned long data)
@@ -1104,14 +1114,14 @@ static void mcheck_timer(unsigned long data)
         * Alert userspace if needed.  If we logged an MCE, reduce the
         * polling interval, otherwise increase the polling interval.
         */
-       n = &__get_cpu_var(next_interval);
+       n = &__get_cpu_var(mce_next_interval);
        if (mce_notify_irq())
                *n = max(*n/2, HZ/100);
        else
                *n = min(*n*2, (int)round_jiffies_relative(check_interval*HZ));
 
        t->expires = jiffies + *n;
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 static void mce_do_trigger(struct work_struct *work)
@@ -1235,8 +1245,13 @@ static void mce_init(void)
 }
 
 /* Add per CPU specific workarounds here */
-static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
+static int __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
 {
+       if (c->x86_vendor == X86_VENDOR_UNKNOWN) {
+               pr_info("MCE: unknown CPU type - not enabling MCE support.\n");
+               return -EOPNOTSUPP;
+       }
+
        /* This should be disabled by the BIOS, but isn't always */
        if (c->x86_vendor == X86_VENDOR_AMD) {
                if (c->x86 == 15 && banks > 4) {
@@ -1283,14 +1298,19 @@ static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
                        monarch_timeout < 0)
                        monarch_timeout = USEC_PER_SEC;
 
-               /* There are also broken BIOSes on some Pentium M systems. */
-               if (c->x86 == 6 && c->x86_model == 13 && mce_bootlog < 0)
+               /*
+                * There are also broken BIOSes on some Pentium M and
+                * earlier systems:
+                */
+               if (c->x86 == 6 && c->x86_model <= 13 && mce_bootlog < 0)
                        mce_bootlog = 0;
        }
        if (monarch_timeout < 0)
                monarch_timeout = 0;
        if (mce_bootlog != 0)
                mce_panic_timeout = 30;
+
+       return 0;
 }
 
 static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
@@ -1324,7 +1344,7 @@ static void mce_cpu_features(struct cpuinfo_x86 *c)
 static void mce_init_timer(void)
 {
        struct timer_list *t = &__get_cpu_var(mce_timer);
-       int *n = &__get_cpu_var(next_interval);
+       int *n = &__get_cpu_var(mce_next_interval);
 
        if (mce_ignore_ce)
                return;
@@ -1334,7 +1354,7 @@ static void mce_init_timer(void)
                return;
        setup_timer(t, mcheck_timer, smp_processor_id());
        t->expires = round_jiffies(jiffies + *n);
-       add_timer(t);
+       add_timer_on(t, smp_processor_id());
 }
 
 /* Handle unconfigured int18 (should never happen) */
@@ -1362,11 +1382,10 @@ void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
        if (!mce_available(c))
                return;
 
-       if (mce_cap_init() < 0) {
+       if (mce_cap_init() < 0 || mce_cpu_quirks(c) < 0) {
                mce_disabled = 1;
                return;
        }
-       mce_cpu_quirks(c);
 
        machine_check_vector = do_machine_check;
 
@@ -1720,17 +1739,15 @@ static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
                                const char *buf, size_t siz)
 {
        char *p;
-       int len;
 
        strncpy(mce_helper, buf, sizeof(mce_helper));
        mce_helper[sizeof(mce_helper)-1] = 0;
-       len = strlen(mce_helper);
        p = strchr(mce_helper, '\n');
 
-       if (*p)
+       if (p)
                *p = 0;
 
-       return len;
+       return strlen(mce_helper) + !!p;
 }
 
 static ssize_t set_ignore_ce(struct sys_device *s,
@@ -1944,7 +1961,7 @@ mce_cpu_callback(struct notifier_block *nfb, unsigned long action, void *hcpu)
        case CPU_DOWN_FAILED:
        case CPU_DOWN_FAILED_FROZEN:
                t->expires = round_jiffies(jiffies +
-                                               __get_cpu_var(next_interval));
+                                          __get_cpu_var(mce_next_interval));
                add_timer_on(t, cpu);
                smp_call_function_single(cpu, mce_reenable_cpu, &action, 1);
                break;