v2.4.9.2 -> v2.4.9.3
[opensuse:kernel.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 <asm/processor.h> 
7 #include <asm/msr.h>
8
9 /*
10  *      Machine Check Handler For PII/PIII
11  */
12
13 static int banks;
14
15 static void intel_machine_check(struct pt_regs * regs, long error_code)
16 {
17         int recover=1;
18         u32 alow, ahigh, high, low;
19         u32 mcgstl, mcgsth;
20         int i;
21         
22         rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
23         if(mcgstl&(1<<0))       /* Recoverable ? */
24                 recover=0;
25
26         printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n", smp_processor_id(), mcgsth, mcgstl);
27         
28         for(i=0;i<banks;i++)
29         {
30                 rdmsr(MSR_IA32_MC0_STATUS+i*4,low, high);
31                 if(high&(1<<31))
32                 {
33                         if(high&(1<<29))
34                                 recover|=1;
35                         if(high&(1<<25))
36                                 recover|=2;
37                         printk(KERN_EMERG "Bank %d: %08x%08x", i, high, low);
38                         high&=~(1<<31);
39                         if(high&(1<<27))
40                         {
41                                 rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
42                                 printk("[%08x%08x]", alow, ahigh);
43                         }
44                         if(high&(1<<26))
45                         {
46                                 rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
47                                 printk(" at %08x%08x", 
48                                         high, low);
49                         }
50                         printk("\n");
51                         /* Clear it */
52                         wrmsr(MSR_IA32_MC0_STATUS+i*4, 0UL, 0UL);
53                         /* Serialize */
54                         wmb();
55                 }
56         }
57         
58         if(recover&2)
59                 panic("CPU context corrupt");
60         if(recover&1)
61                 panic("Unable to continue");
62         printk(KERN_EMERG "Attempting to continue.\n");
63         mcgstl&=~(1<<2);
64         wrmsr(MSR_IA32_MCG_STATUS,mcgstl, mcgsth);
65 }
66
67 /*
68  *      Machine check handler for Pentium class Intel
69  */
70  
71 static void pentium_machine_check(struct pt_regs * regs, long error_code)
72 {
73         u32 loaddr, hi, lotype;
74         rdmsr(MSR_IA32_P5_MC_ADDR, loaddr, hi);
75         rdmsr(MSR_IA32_P5_MC_TYPE, lotype, hi);
76         printk(KERN_EMERG "CPU#%d: Machine Check Exception:  0x%8X (type 0x%8X).\n", smp_processor_id(), loaddr, lotype);
77         if(lotype&(1<<5))
78                 printk(KERN_EMERG "CPU#%d: Possible thermal failure (CPU on fire ?).\n", smp_processor_id());
79 }
80
81 /*
82  *      Machine check handler for WinChip C6
83  */
84  
85 static void winchip_machine_check(struct pt_regs * regs, long error_code)
86 {
87         printk(KERN_EMERG "CPU#%d: Machine Check Exception.\n", smp_processor_id());
88 }
89
90 /*
91  *      Handle unconfigured int18 (should never happen)
92  */
93
94 static void unexpected_machine_check(struct pt_regs * regs, long error_code)
95 {       
96         printk(KERN_ERR "CPU#%d: Unexpected int18 (Machine Check).\n", smp_processor_id());
97 }
98
99 /*
100  *      Call the installed machine check handler for this CPU setup.
101  */ 
102  
103 static void (*machine_check_vector)(struct pt_regs *, long error_code) = unexpected_machine_check;
104
105 void do_machine_check(struct pt_regs * regs, long error_code)
106 {
107         machine_check_vector(regs, error_code);
108 }
109
110 /*
111  *      Set up machine check reporting for Intel processors
112  */
113
114 void __init intel_mcheck_init(struct cpuinfo_x86 *c)
115 {
116         u32 l, h;
117         int i;
118         static int done;
119         
120         /*
121          *      Check for MCE support
122          */
123
124         if( !test_bit(X86_FEATURE_MCE, &c->x86_capability) )
125                 return; 
126         
127         /*
128          *      Pentium machine check
129          */
130         
131         if(c->x86 == 5)
132         {
133                 machine_check_vector = pentium_machine_check;
134                 wmb();
135                 /* Read registers before enabling */
136                 rdmsr(MSR_IA32_P5_MC_ADDR, l, h);
137                 rdmsr(MSR_IA32_P5_MC_TYPE, l, h);
138                 if(done==0)
139                         printk(KERN_INFO "Intel old style machine check architecture supported.\n");
140                 /* Enable MCE */                
141                 __asm__ __volatile__ (
142                         "movl %%cr4, %%eax\n\t"
143                         "orl $0x40, %%eax\n\t"
144                         "movl %%eax, %%cr4\n\t" : : : "eax");
145                 printk(KERN_INFO "Intel old style machine check reporting enabled on CPU#%d.\n", smp_processor_id());
146                 return;
147         }
148         
149
150         /*
151          *      Check for PPro style MCA
152          */
153                         
154         if( !test_bit(X86_FEATURE_MCA, &c->x86_capability) )
155                 return;
156                 
157         /* Ok machine check is available */
158         
159         machine_check_vector = intel_machine_check;
160         wmb();
161         
162         if(done==0)
163                 printk(KERN_INFO "Intel machine check architecture supported.\n");
164         rdmsr(MSR_IA32_MCG_CAP, l, h);
165         if(l&(1<<8))
166                 wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
167         banks = l&0xff;
168         for(i=1;i<banks;i++)
169         {
170                 wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
171         }
172         for(i=0;i<banks;i++)
173         {
174                 wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
175         }
176         set_in_cr4(X86_CR4_MCE);
177         printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n", smp_processor_id());
178         done=1;
179 }
180
181 /*
182  *      Set up machine check reporting on the Winchip C6 series
183  */
184  
185 static void __init winchip_mcheck_init(struct cpuinfo_x86 *c)
186 {
187         u32 lo, hi;
188         /* Not supported on C3 */
189         if(c->x86 != 5)
190                 return;
191         /* Winchip C6 */
192         machine_check_vector = winchip_machine_check;
193         wmb();
194         rdmsr(MSR_IDT_FCR1, lo, hi);
195         lo|= (1<<2);    /* Enable EIERRINT (int 18 MCE) */
196         lo&= ~(1<<4);   /* Enable MCE */
197         wrmsr(MSR_IDT_FCR1, lo, hi);
198         __asm__ __volatile__ (
199                 "movl %%cr4, %%eax\n\t"
200                 "orl $0x40, %%eax\n\t"
201                 "movl %%eax, %%cr4\n\t" : : : "eax");
202         printk(KERN_INFO "Winchip machine check reporting enabled on CPU#%d.\n", smp_processor_id());
203 }
204
205
206 /*
207  *      This has to be run for each processor
208  */
209
210
211 static int mce_disabled = 0;
212
213 void __init mcheck_init(struct cpuinfo_x86 *c)
214 {
215         if(mce_disabled)
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         }
234 }
235
236 static int __init mcheck_disable(char *str)
237 {
238         mce_disabled = 1;
239         return 0;
240 }
241 __setup("nomce", mcheck_disable);