import of upstream 2.4.34.4 from kernel.org
[linux-2.4.git] / arch / i386 / kernel / bluesmoke.c
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
12 static int mce_disabled __initdata = 0;
13
14 /*
15  *      Machine Check Handler For PII/PIII
16  */
17
18 static int banks;
19
20 static 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  
75 static 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  
89 static 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
98 static 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
107 static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
108
109 asmlinkage 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
118 static 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  
189 static 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
213 void __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 || 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
238 static int __init mcheck_disable(char *str)
239 {
240         mce_disabled = 1;
241         return 0;
242 }
243
244 static 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
254 asmlinkage void do_machine_check(struct pt_regs * regs, long error_code) {}
255 void __init mcheck_init(struct cpuinfo_x86 *c) {}
256 #endif