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