]> Pileus Git - ~andy/linux/blob - arch/x86/kernel/cpu/mcheck/p4.c
Merge branch 'for-linus' of git://git.kernel.org/pub/scm/linux/kernel/git/jikos/trivial
[~andy/linux] / arch / x86 / kernel / cpu / mcheck / p4.c
1 /*
2  * P4 specific Machine Check Exception Reporting
3  */
4
5 #include <linux/interrupt.h>
6 #include <linux/kernel.h>
7 #include <linux/types.h>
8 #include <linux/init.h>
9 #include <linux/smp.h>
10
11 #include <asm/therm_throt.h>
12 #include <asm/processor.h>
13 #include <asm/system.h>
14 #include <asm/apic.h>
15 #include <asm/msr.h>
16
17 #include "mce.h"
18
19 /* as supported by the P4/Xeon family */
20 struct intel_mce_extended_msrs {
21         u32 eax;
22         u32 ebx;
23         u32 ecx;
24         u32 edx;
25         u32 esi;
26         u32 edi;
27         u32 ebp;
28         u32 esp;
29         u32 eflags;
30         u32 eip;
31         /* u32 *reserved[]; */
32 };
33
34 static int mce_num_extended_msrs;
35
36
37 #ifdef CONFIG_X86_MCE_P4THERMAL
38
39 static void unexpected_thermal_interrupt(struct pt_regs *regs)
40 {
41         printk(KERN_ERR "CPU%d: Unexpected LVT TMR interrupt!\n",
42                         smp_processor_id());
43         add_taint(TAINT_MACHINE_CHECK);
44 }
45
46 /* P4/Xeon Thermal transition interrupt handler: */
47 static void intel_thermal_interrupt(struct pt_regs *regs)
48 {
49         __u64 msr_val;
50
51         ack_APIC_irq();
52
53         rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
54         therm_throt_process(msr_val & THERM_STATUS_PROCHOT);
55 }
56
57 /* Thermal interrupt handler for this CPU setup: */
58 static void (*vendor_thermal_interrupt)(struct pt_regs *regs) =
59                                                 unexpected_thermal_interrupt;
60
61 void smp_thermal_interrupt(struct pt_regs *regs)
62 {
63         irq_enter();
64         vendor_thermal_interrupt(regs);
65         __get_cpu_var(irq_stat).irq_thermal_count++;
66         irq_exit();
67 }
68
69 void intel_set_thermal_handler(void)
70 {
71         vendor_thermal_interrupt = intel_thermal_interrupt;
72 }
73
74 #endif /* CONFIG_X86_MCE_P4THERMAL */
75
76 /* P4/Xeon Extended MCE MSR retrieval, return 0 if unsupported */
77 static void intel_get_extended_msrs(struct intel_mce_extended_msrs *r)
78 {
79         u32 h;
80
81         rdmsr(MSR_IA32_MCG_EAX, r->eax, h);
82         rdmsr(MSR_IA32_MCG_EBX, r->ebx, h);
83         rdmsr(MSR_IA32_MCG_ECX, r->ecx, h);
84         rdmsr(MSR_IA32_MCG_EDX, r->edx, h);
85         rdmsr(MSR_IA32_MCG_ESI, r->esi, h);
86         rdmsr(MSR_IA32_MCG_EDI, r->edi, h);
87         rdmsr(MSR_IA32_MCG_EBP, r->ebp, h);
88         rdmsr(MSR_IA32_MCG_ESP, r->esp, h);
89         rdmsr(MSR_IA32_MCG_EFLAGS, r->eflags, h);
90         rdmsr(MSR_IA32_MCG_EIP, r->eip, h);
91 }
92
93 static void intel_machine_check(struct pt_regs *regs, long error_code)
94 {
95         u32 alow, ahigh, high, low;
96         u32 mcgstl, mcgsth;
97         int recover = 1;
98         int i;
99
100         rdmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
101         if (mcgstl & (1<<0))    /* Recoverable ? */
102                 recover = 0;
103
104         printk(KERN_EMERG "CPU %d: Machine Check Exception: %08x%08x\n",
105                 smp_processor_id(), mcgsth, mcgstl);
106
107         if (mce_num_extended_msrs > 0) {
108                 struct intel_mce_extended_msrs dbg;
109
110                 intel_get_extended_msrs(&dbg);
111
112                 printk(KERN_DEBUG "CPU %d: EIP: %08x EFLAGS: %08x\n"
113                         "\teax: %08x ebx: %08x ecx: %08x edx: %08x\n"
114                         "\tesi: %08x edi: %08x ebp: %08x esp: %08x\n",
115                         smp_processor_id(), dbg.eip, dbg.eflags,
116                         dbg.eax, dbg.ebx, dbg.ecx, dbg.edx,
117                         dbg.esi, dbg.edi, dbg.ebp, dbg.esp);
118         }
119
120         for (i = 0; i < nr_mce_banks; i++) {
121                 rdmsr(MSR_IA32_MC0_STATUS+i*4, low, high);
122                 if (high & (1<<31)) {
123                         char misc[20];
124                         char addr[24];
125
126                         misc[0] = addr[0] = '\0';
127                         if (high & (1<<29))
128                                 recover |= 1;
129                         if (high & (1<<25))
130                                 recover |= 2;
131                         high &= ~(1<<31);
132                         if (high & (1<<27)) {
133                                 rdmsr(MSR_IA32_MC0_MISC+i*4, alow, ahigh);
134                                 snprintf(misc, 20, "[%08x%08x]", ahigh, alow);
135                         }
136                         if (high & (1<<26)) {
137                                 rdmsr(MSR_IA32_MC0_ADDR+i*4, alow, ahigh);
138                                 snprintf(addr, 24, " at %08x%08x", ahigh, alow);
139                         }
140                         printk(KERN_EMERG "CPU %d: Bank %d: %08x%08x%s%s\n",
141                                 smp_processor_id(), i, high, low, misc, addr);
142                 }
143         }
144
145         if (recover & 2)
146                 panic("CPU context corrupt");
147         if (recover & 1)
148                 panic("Unable to continue");
149
150         printk(KERN_EMERG "Attempting to continue.\n");
151
152         /*
153          * Do not clear the MSR_IA32_MCi_STATUS if the error is not
154          * recoverable/continuable.This will allow BIOS to look at the MSRs
155          * for errors if the OS could not log the error.
156          */
157         for (i = 0; i < nr_mce_banks; i++) {
158                 u32 msr;
159                 msr = MSR_IA32_MC0_STATUS+i*4;
160                 rdmsr(msr, low, high);
161                 if (high&(1<<31)) {
162                         /* Clear it */
163                         wrmsr(msr, 0UL, 0UL);
164                         /* Serialize */
165                         wmb();
166                         add_taint(TAINT_MACHINE_CHECK);
167                 }
168         }
169         mcgstl &= ~(1<<2);
170         wrmsr(MSR_IA32_MCG_STATUS, mcgstl, mcgsth);
171 }
172
173 void intel_p4_mcheck_init(struct cpuinfo_x86 *c)
174 {
175         u32 l, h;
176         int i;
177
178         machine_check_vector = intel_machine_check;
179         wmb();
180
181         printk(KERN_INFO "Intel machine check architecture supported.\n");
182         rdmsr(MSR_IA32_MCG_CAP, l, h);
183         if (l & (1<<8)) /* Control register present ? */
184                 wrmsr(MSR_IA32_MCG_CTL, 0xffffffff, 0xffffffff);
185         nr_mce_banks = l & 0xff;
186
187         for (i = 0; i < nr_mce_banks; i++) {
188                 wrmsr(MSR_IA32_MC0_CTL+4*i, 0xffffffff, 0xffffffff);
189                 wrmsr(MSR_IA32_MC0_STATUS+4*i, 0x0, 0x0);
190         }
191
192         set_in_cr4(X86_CR4_MCE);
193         printk(KERN_INFO "Intel machine check reporting enabled on CPU#%d.\n",
194                 smp_processor_id());
195
196         /* Check for P4/Xeon extended MCE MSRs */
197         rdmsr(MSR_IA32_MCG_CAP, l, h);
198         if (l & (1<<9)) {/* MCG_EXT_P */
199                 mce_num_extended_msrs = (l >> 16) & 0xff;
200                 printk(KERN_INFO "CPU%d: Intel P4/Xeon Extended MCE MSRs (%d)"
201                                 " available\n",
202                         smp_processor_id(), mce_num_extended_msrs);
203
204 #ifdef CONFIG_X86_MCE_P4THERMAL
205                 /* Check for P4/Xeon Thermal monitor */
206                 intel_init_thermal(c);
207 #endif
208         }
209 }