Merge branches 'x86/acpi', 'x86/apic', 'x86/asm', 'x86/cleanups', 'x86/mm', 'x86...
[linux-2.6] / arch / x86 / kernel / cpu / mcheck / mce_intel_64.c
1 /*
2  * Intel specific MCE features.
3  * Copyright 2004 Zwane Mwaikambo <zwane@linuxpower.ca>
4  */
5
6 #include <linux/init.h>
7 #include <linux/interrupt.h>
8 #include <linux/percpu.h>
9 #include <asm/processor.h>
10 #include <asm/apic.h>
11 #include <asm/msr.h>
12 #include <asm/mce.h>
13 #include <asm/hw_irq.h>
14 #include <asm/idle.h>
15 #include <asm/therm_throt.h>
16
17 asmlinkage void smp_thermal_interrupt(void)
18 {
19         __u64 msr_val;
20
21         ack_APIC_irq();
22
23         exit_idle();
24         irq_enter();
25
26         rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
27         if (therm_throt_process(msr_val & 1))
28                 mce_log_therm_throt_event(smp_processor_id(), msr_val);
29
30         inc_irq_stat(irq_thermal_count);
31         irq_exit();
32 }
33
34 static void intel_init_thermal(struct cpuinfo_x86 *c)
35 {
36         u32 l, h;
37         int tm2 = 0;
38         unsigned int cpu = smp_processor_id();
39
40         if (!cpu_has(c, X86_FEATURE_ACPI))
41                 return;
42
43         if (!cpu_has(c, X86_FEATURE_ACC))
44                 return;
45
46         /* first check if TM1 is already enabled by the BIOS, in which
47          * case there might be some SMM goo which handles it, so we can't even
48          * put a handler since it might be delivered via SMI already.
49          */
50         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
51         h = apic_read(APIC_LVTTHMR);
52         if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
53                 printk(KERN_DEBUG
54                        "CPU%d: Thermal monitoring handled by SMI\n", cpu);
55                 return;
56         }
57
58         if (cpu_has(c, X86_FEATURE_TM2) && (l & MSR_IA32_MISC_ENABLE_TM2))
59                 tm2 = 1;
60
61         if (h & APIC_VECTOR_MASK) {
62                 printk(KERN_DEBUG
63                        "CPU%d: Thermal LVT vector (%#x) already "
64                        "installed\n", cpu, (h & APIC_VECTOR_MASK));
65                 return;
66         }
67
68         h = THERMAL_APIC_VECTOR;
69         h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
70         apic_write(APIC_LVTTHMR, h);
71
72         rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
73         wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
74
75         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
76         wrmsr(MSR_IA32_MISC_ENABLE, l | MSR_IA32_MISC_ENABLE_TM1, h);
77
78         l = apic_read(APIC_LVTTHMR);
79         apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
80         printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
81                 cpu, tm2 ? "TM2" : "TM1");
82
83         /* enable thermal throttle processing */
84         atomic_set(&therm_throt_en, 1);
85         return;
86 }
87
88 void mce_intel_feature_init(struct cpuinfo_x86 *c)
89 {
90         intel_init_thermal(c);
91 }