Commit | Line | Data |
---|---|---|
1da177e4 LT |
1 | /* |
2 | * P6 specific Machine Check Exception Reporting | |
87c6fe26 | 3 | * (C) Copyright 2002 Alan Cox <alan@lxorguk.ukuu.org.uk> |
1da177e4 | 4 | */ |
1da177e4 | 5 | #include <linux/interrupt.h> |
ea2566ff IM |
6 | #include <linux/kernel.h> |
7 | #include <linux/types.h> | |
8 | #include <linux/init.h> | |
1da177e4 LT |
9 | #include <linux/smp.h> |
10 | ||
2c584783 | 11 | #include <asm/processor.h> |
1da177e4 | 12 | #include <asm/system.h> |
9e55e44e | 13 | #include <asm/mce.h> |
1da177e4 LT |
14 | #include <asm/msr.h> |
15 | ||
1da177e4 | 16 | /* Machine Check Handler For PII/PIII */ |
2c584783 | 17 | static void intel_machine_check(struct pt_regs *regs, long error_code) |
1da177e4 | 18 | { |
1da177e4 LT |
19 | u32 alow, ahigh, high, low; |
20 | u32 mcgstl, mcgsth; | |
ea2566ff | 21 | int recover = 1; |
1da177e4 LT |
22 | int i; |
23 | ||
2c584783 | 24 | rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); |
1da177e4 | 25 | if (mcgstl & (1<<0)) /* Recoverable ? */ |
2c584783 | 26 | recover = 0; |
1da177e4 | 27 | |
b912a1c7 | 28 | printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", |
1da177e4 LT |
29 | smp_processor_id(), mcgsth, mcgstl); |
30 | ||
b912a1c7 | 31 | for (i = 0; i < nr_mce_banks; i++) { |
72713393 | 32 | rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high); |
1da177e4 | 33 | if (high & (1<<31)) { |
9e8b6d90 MZ |
34 | char misc[20]; |
35 | char addr[24]; | |
ea2566ff IM |
36 | |
37 | misc[0] = '\0'; | |
38 | addr[0] = '\0'; | |
39 | ||
1da177e4 LT |
40 | if (high & (1<<29)) |
41 | recover |= 1; | |
42 | if (high & (1<<25)) | |
43 | recover |= 2; | |
1da177e4 | 44 | high &= ~(1<<31); |
ea2566ff | 45 | |
1da177e4 | 46 | if (high & (1<<27)) { |
b912a1c7 AM |
47 | rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh); |
48 | snprintf(misc, 20, "[%08x%08x]", ahigh, alow); | |
1da177e4 LT |
49 | } |
50 | if (high & (1<<26)) { | |
b912a1c7 AM |
51 | rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh); |
52 | snprintf(addr, 24, " at %08x%08x", ahigh, alow); | |
1da177e4 | 53 | } |
ea2566ff | 54 | |
b912a1c7 | 55 | printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n", |
9e8b6d90 | 56 | smp_processor_id(), i, high, low, misc, addr); |
1da177e4 LT |
57 | } |
58 | } | |
59 | ||
60 | if (recover & 2) | |
2c584783 | 61 | panic("CPU context corrupt"); |
1da177e4 | 62 | if (recover & 1) |
2c584783 | 63 | panic("Unable to continue"); |
1da177e4 | 64 | |
2c584783 PC |
65 | printk(KERN_EMERG "Attempting to continue.\n"); |
66 | /* | |
67 | * Do not clear the MSR_IA32_MCi_STATUS if the error is not | |
1da177e4 | 68 | * recoverable/continuable.This will allow BIOS to look at the MSRs |
ea2566ff | 69 | * for errors if the OS could not log the error: |
1da177e4 | 70 | */ |
2c584783 | 71 | for (i = 0; i < nr_mce_banks; i++) { |
1da177e4 | 72 | unsigned int msr; |
ea2566ff | 73 | |
1da177e4 | 74 | msr = MSR_IA32_MC0_STATUS+i*4; |
2c584783 | 75 | rdmsr(msr, low, high); |
1da177e4 | 76 | if (high & (1<<31)) { |
ea2566ff | 77 | /* Clear it: */ |
2c584783 | 78 | wrmsr(msr, 0UL, 0UL); |
ea2566ff | 79 | /* Serialize: */ |
1da177e4 LT |
80 | wmb(); |
81 | add_taint(TAINT_MACHINE_CHECK); | |
82 | } | |
83 | } | |
84 | mcgstl &= ~(1<<2); | |
2c584783 | 85 | wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth); |
1da177e4 LT |
86 | } |
87 | ||
ea2566ff | 88 | /* Set up machine check reporting for processors with Intel style MCE: */ |
31ab269a | 89 | void intel_p6_mcheck_init(struct cpuinfo_x86 *c) |
1da177e4 LT |
90 | { |
91 | u32 l, h; | |
92 | int i; | |
2c584783 | 93 | |
1da177e4 LT |
94 | /* Check for MCE support */ |
95 | if (!cpu_has(c, X86_FEATURE_MCE)) | |
96 | return; | |
97 | ||
98 | /* Check for PPro style MCA */ | |
2c584783 | 99 | if (!cpu_has(c, X86_FEATURE_MCA)) |
1da177e4 LT |
100 | return; |
101 | ||
102 | /* Ok machine check is available */ | |
103 | machine_check_vector = intel_machine_check; | |
ea2566ff | 104 | /* Make sure the vector pointer is visible before we enable MCEs: */ |
1da177e4 LT |
105 | wmb(); |
106 | ||
2c584783 PC |
107 | printk(KERN_INFO "Intel machine check architecture supported.\n"); |
108 | rdmsr(MSR_IA32_MCG_CAP, l, h); | |
1da177e4 LT |
109 | if (l & (1<<8)) /* Control register present ? */ |
110 | wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff); | |
111 | nr_mce_banks = l & 0xff; | |
112 | ||
434440a2 VP |
113 | /* |
114 | * Following the example in IA-32 SDM Vol 3: | |
115 | * - MC0_CTL should not be written | |
116 | * - Status registers on all banks should be cleared on reset | |
117 | */ | |
2c584783 PC |
118 | for (i = 1; i < nr_mce_banks; i++) |
119 | wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff); | |
434440a2 | 120 | |
2c584783 PC |
121 | for (i = 0; i < nr_mce_banks; i++) |
122 | wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0); | |
1da177e4 | 123 | |
2c584783 PC |
124 | set_in_cr4(X86_CR4_MCE); |
125 | printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", | |
1da177e4 LT |
126 | smp_processor_id()); |
127 | } |