Merge branch 'master' into for-next
[pandora-kernel.git] / arch / x86 / kernel / cpu / mcheck / mce.c
index e8b893e..20d4983 100644 (file)
@@ -44,7 +44,6 @@
 #include <asm/msr.h>
 
 #include "mce-internal.h"
-#include "mce.h"
 
 /* Handle unconfigured int18 (should never happen) */
 static void unexpected_machine_check(struct pt_regs *regs, long error_code)
@@ -1092,7 +1091,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)
@@ -1111,14 +1110,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)
@@ -1250,7 +1249,7 @@ static void mce_cpu_quirks(struct cpuinfo_x86 *c)
                 * Various K7s with broken bank 0 around. Always disable
                 * by default.
                 */
-                if (c->x86 == 6)
+                if (c->x86 == 6 && banks > 0)
                        bank[0] = 0;
        }
 
@@ -1287,8 +1286,7 @@ static void __cpuinit mce_ancient_init(struct cpuinfo_x86 *c)
                return;
        switch (c->x86_vendor) {
        case X86_VENDOR_INTEL:
-               if (mce_p5_enabled())
-                       intel_p5_mcheck_init(c);
+               intel_p5_mcheck_init(c);
                break;
        case X86_VENDOR_CENTAUR:
                winchip_mcheck_init(c);
@@ -1313,7 +1311,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;
@@ -1323,7 +1321,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());
 }
 
 /*
@@ -1626,6 +1624,26 @@ static void mce_restart(void)
        on_each_cpu(mce_cpu_restart, NULL, 1);
 }
 
+/* Toggle features for corrected errors */
+static void mce_disable_ce(void *all)
+{
+       if (!mce_available(&current_cpu_data))
+               return;
+       if (all)
+               del_timer_sync(&__get_cpu_var(mce_timer));
+       cmci_clear();
+}
+
+static void mce_enable_ce(void *all)
+{
+       if (!mce_available(&current_cpu_data))
+               return;
+       cmci_reenable();
+       cmci_recheck();
+       if (all)
+               mce_init_timer();
+}
+
 static struct sysdev_class mce_sysclass = {
        .suspend        = mce_suspend,
        .shutdown       = mce_shutdown,
@@ -1687,6 +1705,52 @@ static ssize_t set_trigger(struct sys_device *s, struct sysdev_attribute *attr,
        return len;
 }
 
+static ssize_t set_ignore_ce(struct sys_device *s,
+                            struct sysdev_attribute *attr,
+                            const char *buf, size_t size)
+{
+       u64 new;
+
+       if (strict_strtoull(buf, 0, &new) < 0)
+               return -EINVAL;
+
+       if (mce_ignore_ce ^ !!new) {
+               if (new) {
+                       /* disable ce features */
+                       on_each_cpu(mce_disable_ce, (void *)1, 1);
+                       mce_ignore_ce = 1;
+               } else {
+                       /* enable ce features */
+                       mce_ignore_ce = 0;
+                       on_each_cpu(mce_enable_ce, (void *)1, 1);
+               }
+       }
+       return size;
+}
+
+static ssize_t set_cmci_disabled(struct sys_device *s,
+                                struct sysdev_attribute *attr,
+                                const char *buf, size_t size)
+{
+       u64 new;
+
+       if (strict_strtoull(buf, 0, &new) < 0)
+               return -EINVAL;
+
+       if (mce_cmci_disabled ^ !!new) {
+               if (new) {
+                       /* disable cmci */
+                       on_each_cpu(mce_disable_ce, NULL, 1);
+                       mce_cmci_disabled = 1;
+               } else {
+                       /* enable cmci */
+                       mce_cmci_disabled = 0;
+                       on_each_cpu(mce_enable_ce, NULL, 1);
+               }
+       }
+       return size;
+}
+
 static ssize_t store_int_with_restart(struct sys_device *s,
                                      struct sysdev_attribute *attr,
                                      const char *buf, size_t size)
@@ -1699,6 +1763,7 @@ static ssize_t store_int_with_restart(struct sys_device *s,
 static SYSDEV_ATTR(trigger, 0644, show_trigger, set_trigger);
 static SYSDEV_INT_ATTR(tolerant, 0644, tolerant);
 static SYSDEV_INT_ATTR(monarch_timeout, 0644, monarch_timeout);
+static SYSDEV_INT_ATTR(dont_log_ce, 0644, mce_dont_log_ce);
 
 static struct sysdev_ext_attribute attr_check_interval = {
        _SYSDEV_ATTR(check_interval, 0644, sysdev_show_int,
@@ -1706,9 +1771,24 @@ static struct sysdev_ext_attribute attr_check_interval = {
        &check_interval
 };
 
+static struct sysdev_ext_attribute attr_ignore_ce = {
+       _SYSDEV_ATTR(ignore_ce, 0644, sysdev_show_int, set_ignore_ce),
+       &mce_ignore_ce
+};
+
+static struct sysdev_ext_attribute attr_cmci_disabled = {
+       _SYSDEV_ATTR(cmci_disabled, 0644, sysdev_show_int, set_cmci_disabled),
+       &mce_cmci_disabled
+};
+
 static struct sysdev_attribute *mce_attrs[] = {
-       &attr_tolerant.attr, &attr_check_interval.attr, &attr_trigger,
+       &attr_tolerant.attr,
+       &attr_check_interval.attr,
+       &attr_trigger,
        &attr_monarch_timeout.attr,
+       &attr_dont_log_ce.attr,
+       &attr_ignore_ce.attr,
+       &attr_cmci_disabled.attr,
        NULL
 };
 
@@ -1718,7 +1798,7 @@ static cpumask_var_t mce_dev_initialized;
 static __cpuinit int mce_create_device(unsigned int cpu)
 {
        int err;
-       int i;
+       int i, j;
 
        if (!mce_available(&boot_cpu_data))
                return -EIO;
@@ -1736,9 +1816,9 @@ static __cpuinit int mce_create_device(unsigned int cpu)
                if (err)
                        goto error;
        }
-       for (i = 0; i < banks; i++) {
+       for (j = 0; j < banks; j++) {
                err = sysdev_create_file(&per_cpu(mce_dev, cpu),
-                                       &bank_attrs[i]);
+                                       &bank_attrs[j]);
                if (err)
                        goto error2;
        }
@@ -1746,8 +1826,8 @@ static __cpuinit int mce_create_device(unsigned int cpu)
 
        return 0;
 error2:
-       while (--i >= 0)
-               sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[i]);
+       while (--j >= 0)
+               sysdev_remove_file(&per_cpu(mce_dev, cpu), &bank_attrs[j]);
 error:
        while (--i >= 0)
                sysdev_remove_file(&per_cpu(mce_dev, cpu), mce_attrs[i]);
@@ -1834,7 +1914,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;
@@ -1889,7 +1969,7 @@ static __init int mce_init_device(void)
        if (!mce_available(&boot_cpu_data))
                return -EIO;
 
-       alloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL);
+       zalloc_cpumask_var(&mce_dev_initialized, GFP_KERNEL);
 
        err = mce_init_banks();
        if (err)
@@ -1921,7 +2001,7 @@ EXPORT_SYMBOL_GPL(nr_mce_banks);  /* non-fatal.o */
 /* This has to be run for each processor */
 void mcheck_init(struct cpuinfo_x86 *c)
 {
-       if (mce_disabled == 1)
+       if (mce_disabled)
                return;
 
        switch (c->x86_vendor) {
@@ -1951,10 +2031,9 @@ void mcheck_init(struct cpuinfo_x86 *c)
 
 static int __init mcheck_enable(char *str)
 {
-       mce_disabled = -1;
+       mce_p5_enabled = 1;
        return 1;
 }
-
 __setup("mce", mcheck_enable);
 
 #endif /* CONFIG_X86_OLD_MCE */