46dd17daa174f43ab44304a416b068f2b72d677a
[linux-flexiantxendom0-3.2.10.git] / arch / i386 / kernel / cpu / mcheck / non-fatal.c
1 /*
2  * Non Fatal Machine Check Exception Reporting
3  *
4  * (C) Copyright 2002 Dave Jones. <davej@codemonkey.org.uk>
5  *
6  * This file contains routines to check for non-fatal MCEs every 15s
7  *
8  */
9
10 #include <linux/init.h>
11 #include <linux/types.h>
12 #include <linux/kernel.h>
13 #include <linux/jiffies.h>
14 #include <linux/config.h>
15 #include <linux/irq.h>
16 #include <linux/workqueue.h>
17 #include <linux/interrupt.h>
18 #include <linux/smp.h>
19 #include <linux/module.h>
20
21 #include <asm/processor.h> 
22 #include <asm/system.h>
23 #include <asm/msr.h>
24
25 #include "mce.h"
26
27 static struct timer_list mce_timer;
28 static int timerset;
29 static int firstbank;
30
31 #define MCE_RATE        15*HZ   /* timer rate is 15s */
32
33 static void mce_checkregs (void *info)
34 {
35         u32 low, high;
36         int i;
37
38         preempt_disable(); 
39         for (i=firstbank; i<nr_mce_banks; i++) {
40                 rdmsr (MSR_IA32_MC0_STATUS+i*4, low, high);
41
42                 if (high & (1<<31)) {
43                         printk (KERN_EMERG "MCE: The hardware reports a non fatal, correctable incident occurred on CPU %d.\n",
44                                 smp_processor_id());
45                         printk (KERN_EMERG "Bank %d: %08x%08x\n", i, high, low);
46
47                         /* Scrub the error so we don't pick it up in MCE_RATE seconds time. */
48                         wrmsr (MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
49
50                         /* Serialize */
51                         wmb();
52                 }
53         }
54         preempt_enable();
55 }
56
57 static void do_mce_timer(void *data)
58
59         smp_call_function (mce_checkregs, NULL, 1, 1);
60
61
62 static DECLARE_WORK(mce_work, do_mce_timer, NULL);
63
64 static void mce_timerfunc (unsigned long data)
65 {
66         mce_checkregs (NULL);
67 #ifdef CONFIG_SMP
68         if (num_online_cpus() > 1) 
69                 schedule_work (&mce_work); 
70 #endif
71         mce_timer.expires = jiffies + MCE_RATE;
72         add_timer (&mce_timer);
73 }       
74
75 static int __init init_nonfatal_mce_checker(void)
76 {
77         struct cpuinfo_x86 *c = &boot_cpu_data;
78
79         /* Check for MCE support */
80         if (!cpu_has(c, X86_FEATURE_MCE))
81                 return -ENODEV;
82
83         /* Check for PPro style MCA */
84         if (!cpu_has(c, X86_FEATURE_MCA))
85                 return -ENODEV;
86
87         /* Some Athlons misbehave when we frob bank 0 */
88         if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD &&
89                 boot_cpu_data.x86 == 6)
90                         firstbank = 1;
91         else
92                         firstbank = 0;
93
94         if (timerset == 0) {
95                 /* Set the timer to check for non-fatal
96                    errors every MCE_RATE seconds */
97                 init_timer (&mce_timer);
98                 mce_timer.expires = jiffies + MCE_RATE;
99                 mce_timer.data = 0;
100                 mce_timer.function = &mce_timerfunc;
101                 add_timer (&mce_timer);
102                 timerset = 1;
103                 printk(KERN_INFO "Machine check exception polling timer started.\n");
104         }
105         return 0;
106 }
107 module_init(init_nonfatal_mce_checker);