1
2#include <linux/init.h>
3#include <linux/types.h>
4#include <linux/kernel.h>
5#include <linux/sched.h>
6#include <linux/config.h>
7#include <asm/processor.h>
8#include <asm/msr.h>
9
10#ifdef CONFIG_X86_MCE
11
12static int mce_disabled __initdata = 0;
13
14
15
16
17
18static int banks;
19
20static void intel_machine_check(struct pt_regs * regs, long error_code)
21{
22 int recover=1;
23 u32 alow, ahigh, high, low;
24 u32 mcgstl, mcgsth;
25 int i;
26
27 rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
28 if(mcgstl&(1<<0))
29 recover=0;
30
31 printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
32
33 for(i=0;i<banks;i++)
34 {
35 rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
36 if(high&(1<<31))
37 {
38 if(high&(1<<29))
39 recover|=1;
40 if(high&(1<<25))
41 recover|=2;
42 printk(KERN_EMERG "Bank %d: %08x%08x", i, high, low);
43 high&=~(1<<31);
44 if(high&(1<<27))
45 {
46 rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
47 printk("[%08x%08x]", ahigh, alow);
48 }
49 if(high&(1<<26))
50 {
51 rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
52 printk(" at %08x%08x", ahigh, alow);
53 }
54 printk("\n");
55
56 wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
57
58 wmb();
59 }
60 }
61
62 if(recover&2)
63 panic("CPU context corrupt");
64 if(recover&1)
65 panic("Unable to continue");
66 printk(KERN_EMERG "Attempting to continue.\n");
67 mcgstl&=~(1<<2);
68 wrmsr(MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
69}
70
71
72
73
74
75static void pentium_machine_check(struct pt_regs * regs, long error_code)
76{
77 u32 loaddr, hi, lotype;
78 rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
79 rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
80 printk(KERN_EMERG "CPU#%d: Machine Check Exception: 0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
81 if(lotype&(1<<5))
82 printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
83}
84
85
86
87
88
89static void winchip_machine_check(struct pt_regs * regs, long error_code)
90{
91 printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id());
92}
93
94
95
96
97
98static void unexpected_machine_check(struct pt_regs * regs, long error_code)
99{
100 printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
101}
102
103
104
105
106
107static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
108
109asmlinkage void do_machine_check(struct pt_regs * regs, long error_code)
110{
111 machine_check_vector(regs, error_code);
112}
113
114
115
116
117
118static void __init intel_mcheck_init(struct cpuinfo_x86 *c)
119{
120 u32 l, h;
121 int i;
122 static int done;
123
124
125
126
127
128 if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
129 return;
130
131
132
133
134
135 if(c->x86 == 5)
136 {
137
138 if(mce_disabled != -1)
139 return;
140 machine_check_vector = pentium_machine_check;
141 wmb();
142
143 rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
144 rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
145 if(done==0)
146 printk(KERN_INFO "Intel old style machine check architecture supported.\n");
147
148 set_in_cr4(X86_CR4_MCE);
149 printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
150 return;
151 }
152
153
154
155
156
157
158 if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
159 return;
160
161
162
163 machine_check_vector = intel_machine_check;
164 wmb();
165
166 if(done==0)
167 printk(KERN_INFO "Intel machine check architecture supported.\n");
168 rdmsr(MSR_IA32_MCG_CAP, l, h);
169 if(l&(1<<8))
170 wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
171 banks = l&0xff;
172 for(i=1;i<banks;i++)
173 {
174 wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
175 }
176 for(i=0;i<banks;i++)
177 {
178 wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
179 }
180 set_in_cr4(X86_CR4_MCE);
181 printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
182 done=1;
183}
184
185
186
187
188
189static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
190{
191 u32 lo, hi;
192
193 if(c->x86 != 5)
194 return;
195
196 machine_check_vector = winchip_machine_check;
197 wmb();
198 rdmsr(MSR_IDT_FCR1, lo, hi);
199 lo|= (1<<2);
200 lo&= ~(1<<4);
201 wrmsr(MSR_IDT_FCR1, lo, hi);
202 set_in_cr4(X86_CR4_MCE);
203 printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
204}
205
206
207
208
209
210
211
212
213void __init mcheck_init(struct cpuinfo_x86 *c)
214{
215 if(mce_disabled==1)
216 return;
217
218 switch(c->x86_vendor)
219 {
220 case X86_VENDOR_AMD:
221
222
223
224 if(c->x86 == 6 || c->x86 == 15)
225 intel_mcheck_init(c);
226 break;
227 case X86_VENDOR_INTEL:
228 intel_mcheck_init(c);
229 break;
230 case X86_VENDOR_CENTAUR:
231 winchip_mcheck_init(c);
232 break;
233 default:
234 break;
235 }
236}
237
238static int __init mcheck_disable(char *str)
239{
240 mce_disabled = 1;
241 return 0;
242}
243
244static int __init mcheck_enable(char *str)
245{
246 mce_disabled = -1;
247 return 0;
248}
249
250__setup("nomce", mcheck_disable);
251__setup("mce", mcheck_enable);
252
253#else
254asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {}
255void __init mcheck_init(struct cpuinfo_x86 *c) {}
256#endif
257