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