Merge branch 'for-linus' of git://www.atmel.no/~hskinnemoen/linux/kernel/avr32
[linux-2.6] / arch / x86_64 / kernel / mce_intel.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         irq_exit();
30 }
31
32 static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
33 {
34         u32 l, h;
35         int tm2 = 0;
36         unsigned int cpu = smp_processor_id();
37
38         if (!cpu_has(c, X86_FEATURE_ACPI))
39                 return;
40
41         if (!cpu_has(c, X86_FEATURE_ACC))
42                 return;
43
44         /* first check if TM1 is already enabled by the BIOS, in which
45          * case there might be some SMM goo which handles it, so we can't even
46          * put a handler since it might be delivered via SMI already.
47          */
48         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
49         h = apic_read(APIC_LVTTHMR);
50         if ((l & (1 << 3)) && (h & APIC_DM_SMI)) {
51                 printk(KERN_DEBUG
52                        "CPU%d: Thermal monitoring handled by SMI\n", cpu);
53                 return;
54         }
55
56         if (cpu_has(c, X86_FEATURE_TM2) && (l & (1 << 13)))
57                 tm2 = 1;
58
59         if (h & APIC_VECTOR_MASK) {
60                 printk(KERN_DEBUG
61                        "CPU%d: Thermal LVT vector (%#x) already "
62                        "installed\n", cpu, (h & APIC_VECTOR_MASK));
63                 return;
64         }
65
66         h = THERMAL_APIC_VECTOR;
67         h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
68         apic_write(APIC_LVTTHMR, h);
69
70         rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
71         wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
72
73         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
74         wrmsr(MSR_IA32_MISC_ENABLE, l | (1 << 3), h);
75
76         l = apic_read(APIC_LVTTHMR);
77         apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
78         printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
79                 cpu, tm2 ? "TM2" : "TM1");
80
81         /* enable thermal throttle processing */
82         atomic_set(&therm_throt_en, 1);
83         return;
84 }
85
86 void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
87 {
88         intel_init_thermal(c);
89 }