]> pilppa.org Git - linux-2.6-omap-h63xx.git/blobdiff - arch/x86_64/kernel/mce.c
Merge git://git.kernel.org/pub/scm/linux/kernel/git/sam/kbuild-bugfix
[linux-2.6-omap-h63xx.git] / arch / x86_64 / kernel / mce.c
index 69541db5ff2c46ae58d199ab3ed695fbf7165572..b8b9529fa89e0db08b90cc6d6bea4da6fa7e0afb 100644 (file)
@@ -15,6 +15,7 @@
 #include <linux/sysdev.h>
 #include <linux/miscdevice.h>
 #include <linux/fs.h>
+#include <linux/capability.h>
 #include <linux/cpu.h>
 #include <linux/percpu.h>
 #include <linux/ctype.h>
 #include <asm/mce.h>
 #include <asm/kdebug.h>
 #include <asm/uaccess.h>
+#include <asm/smp.h>
 
 #define MISC_MCELOG_MINOR 227
-#define NR_BANKS 5
+#define NR_BANKS 6
 
 static int mce_dont_init;
 
@@ -37,7 +39,7 @@ static unsigned long bank[NR_BANKS] = { [0 ... NR_BANKS-1] = ~0UL };
 static unsigned long console_logged;
 static int notify_user;
 static int rip_msr;
-static int mce_bootlog;
+static int mce_bootlog = 1;
 
 /*
  * Lockless MCE logging infrastructure.
@@ -91,6 +93,7 @@ void mce_log(struct mce *mce)
 static void print_mce(struct mce *m)
 {
        printk(KERN_EMERG "\n"
+              KERN_EMERG "HARDWARE ERROR\n"
               KERN_EMERG
               "CPU %d: Machine Check Exception: %16Lx Bank %d: %016Lx\n",
               m->cpu, m->mcgstatus, m->bank, m->status);
@@ -109,6 +112,9 @@ static void print_mce(struct mce *m)
        if (m->misc)
                printk("MISC %Lx ", m->misc);   
        printk("\n");
+       printk(KERN_EMERG "This is not a software problem!\n");
+        printk(KERN_EMERG
+    "Run through mcelog --ascii to decode and contact your hardware vendor\n");
 }
 
 static void mce_panic(char *msg, struct mce *backup, unsigned long start)
@@ -168,12 +174,12 @@ void do_machine_check(struct pt_regs * regs, long error_code)
        int panicm_found = 0;
 
        if (regs)
-               notify_die(DIE_NMI, "machine check", regs, error_code, 255, SIGKILL);
+               notify_die(DIE_NMI, "machine check", regs, error_code, 18, SIGKILL);
        if (!banks)
                return;
 
        memset(&m, 0, sizeof(struct mce));
-       m.cpu = hard_smp_processor_id();
+       m.cpu = safe_smp_processor_id();
        rdmsrl(MSR_IA32_MCG_STATUS, m.mcgstatus);
        if (!(m.mcgstatus & MCG_STATUS_RIPV))
                kill_it = 1;
@@ -347,7 +353,11 @@ static void __cpuinit mce_cpu_quirks(struct cpuinfo_x86 *c)
                /* disable GART TBL walk error reporting, which trips off 
                   incorrectly with the IOMMU & 3ware & Cerberus. */
                clear_bit(10, &bank[4]);
+               /* Lots of broken BIOS around that don't clear them
+                  by default and leave crap in there. Don't log. */
+               mce_bootlog = 0;
        }
+
 }                      
 
 static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
@@ -356,6 +366,9 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
        case X86_VENDOR_INTEL:
                mce_intel_feature_init(c);
                break;
+       case X86_VENDOR_AMD:
+               mce_amd_feature_init(c);
+               break;
        default:
                break;
        }
@@ -367,7 +380,7 @@ static void __cpuinit mce_cpu_features(struct cpuinfo_x86 *c)
  */
 void __cpuinit mcheck_init(struct cpuinfo_x86 *c)
 {
-       static cpumask_t mce_cpus __initdata = CPU_MASK_NONE;
+       static cpumask_t mce_cpus = CPU_MASK_NONE;
 
        mce_cpu_quirks(c); 
 
@@ -495,16 +508,16 @@ static int __init mcheck_disable(char *str)
 /* mce=off disables machine check. Note you can reenable it later
    using sysfs.
    mce=TOLERANCELEVEL (number, see above)
-   mce=bootlog Log MCEs from before booting. Disabled by default to work
-   around buggy BIOS that leave bogus MCEs.  */
+   mce=bootlog Log MCEs from before booting. Disabled by default on AMD.
+   mce=nobootlog Don't log MCEs from before booting. */
 static int __init mcheck_enable(char *str)
 {
        if (*str == '=')
                str++;
        if (!strcmp(str, "off"))
                mce_dont_init = 1;
-       else if (!strcmp(str, "bootlog"))
-               mce_bootlog = 1;
+       else if (!strcmp(str, "bootlog") || !strcmp(str,"nobootlog"))
+               mce_bootlog = str[0] == 'b';
        else if (isdigit(str[0]))
                get_option(&str, &tolerant);
        else
@@ -566,6 +579,10 @@ ACCESSOR(bank1ctl,bank[1],mce_restart())
 ACCESSOR(bank2ctl,bank[2],mce_restart())
 ACCESSOR(bank3ctl,bank[3],mce_restart())
 ACCESSOR(bank4ctl,bank[4],mce_restart())
+ACCESSOR(bank5ctl,bank[5],mce_restart())
+static struct sysdev_attribute * bank_attributes[NR_BANKS] = {
+       &attr_bank0ctl, &attr_bank1ctl, &attr_bank2ctl,
+       &attr_bank3ctl, &attr_bank4ctl, &attr_bank5ctl};
 ACCESSOR(tolerant,tolerant,)
 ACCESSOR(check_interval,check_interval,mce_restart())
 
@@ -573,6 +590,7 @@ ACCESSOR(check_interval,check_interval,mce_restart())
 static __cpuinit int mce_create_device(unsigned int cpu)
 {
        int err;
+       int i;
        if (!mce_available(&cpu_data[cpu]))
                return -EIO;
 
@@ -582,11 +600,9 @@ static __cpuinit int mce_create_device(unsigned int cpu)
        err = sysdev_register(&per_cpu(device_mce,cpu));
 
        if (!err) {
-               sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
-               sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
-               sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
-               sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
-               sysdev_create_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
+               for (i = 0; i < banks; i++)
+                       sysdev_create_file(&per_cpu(device_mce,cpu),
+                               bank_attributes[i]);
                sysdev_create_file(&per_cpu(device_mce,cpu), &attr_tolerant);
                sysdev_create_file(&per_cpu(device_mce,cpu), &attr_check_interval);
        }
@@ -596,11 +612,11 @@ static __cpuinit int mce_create_device(unsigned int cpu)
 #ifdef CONFIG_HOTPLUG_CPU
 static __cpuinit void mce_remove_device(unsigned int cpu)
 {
-       sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank0ctl);
-       sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank1ctl);
-       sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank2ctl);
-       sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank3ctl);
-       sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_bank4ctl);
+       int i;
+
+       for (i = 0; i < banks; i++)
+               sysdev_remove_file(&per_cpu(device_mce,cpu),
+                       bank_attributes[i]);
        sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_tolerant);
        sysdev_remove_file(&per_cpu(device_mce,cpu), &attr_check_interval);
        sysdev_unregister(&per_cpu(device_mce,cpu));