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 *	Machine Check Handler For PII/PIII
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))	/* Recoverable ? */
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			/* Clear it */
56			wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
57			/* Serialize */
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 *	Machine check handler for Pentium class Intel
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 *	Machine check handler for WinChip C6
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 *	Handle unconfigured int18 (should never happen)
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 *	Call the installed machine check handler for this CPU setup.
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 *	Set up machine check reporting for Intel processors
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	 *	Check for MCE support
126	 */
127
128	if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
129		return;
130
131	/*
132	 *	Pentium machine check
133	 */
134
135	if(c->x86 == 5)
136	{
137		/* Default P5 to off as its often misconnected */
138		if(mce_disabled != -1)
139			return;
140		machine_check_vector = pentium_machine_check;
141		wmb();
142		/* Read registers before enabling */
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 		/* Enable MCE */
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	 *	Check for PPro style MCA
156	 */
157
158	if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
159		return;
160
161	/* Ok machine check is available */
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 *	Set up machine check reporting on the Winchip C6 series
187 */
188
189static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
190{
191	u32 lo, hi;
192	/* Not supported on C3 */
193	if(c->x86 != 5)
194		return;
195	/* Winchip C6 */
196	machine_check_vector = winchip_machine_check;
197	wmb();
198	rdmsr(MSR_IDT_FCR1, lo, hi);
199	lo|= (1<<2);	/* Enable EIERRINT (int 18 MCE) */
200	lo&= ~(1<<4);	/* Enable MCE */
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 *	This has to be run for each processor
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			 *	AMD K7 machine check is Intel like
223			 */
224			if(c->x86 == 6)
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