Merge master.kernel.org:/pub/scm/linux/kernel/git/davem/net-2.6
[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
14 static DEFINE_PER_CPU(unsigned long, next_check);
15
16 asmlinkage void smp_thermal_interrupt(void)
17 {
18         struct mce m;
19
20         ack_APIC_irq();
21
22         irq_enter();
23         if (time_before(jiffies, __get_cpu_var(next_check)))
24                 goto done;
25
26         __get_cpu_var(next_check) = jiffies + HZ*300;
27         memset(&m, 0, sizeof(m));
28         m.cpu = smp_processor_id();
29         m.bank = MCE_THERMAL_BANK;
30         rdtscll(m.tsc);
31         rdmsrl(MSR_IA32_THERM_STATUS, m.status);
32         if (m.status & 0x1) {
33                 printk(KERN_EMERG
34                         "CPU%d: Temperature above threshold, cpu clock throttled\n", m.cpu);
35                 add_taint(TAINT_MACHINE_CHECK);
36         } else {
37                 printk(KERN_EMERG "CPU%d: Temperature/speed normal\n", m.cpu);
38         }
39
40         mce_log(&m);
41 done:
42         irq_exit();
43 }
44
45 static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
46 {
47         u32 l, h;
48         int tm2 = 0;
49         unsigned int cpu = smp_processor_id();
50
51         if (!cpu_has(c, X86_FEATURE_ACPI))
52                 return;
53
54         if (!cpu_has(c, X86_FEATURE_ACC))
55                 return;
56
57         /* first check if TM1 is already enabled by the BIOS, in which
58          * case there might be some SMM goo which handles it, so we can't even
59          * put a handler since it might be delivered via SMI already.
60          */
61         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
62         h = apic_read(APIC_LVTTHMR);
63         if ((l & (1 << 3)) && (h & APIC_DM_SMI)) {
64                 printk(KERN_DEBUG
65                        "CPU%d: Thermal monitoring handled by SMI\n", cpu);
66                 return;
67         }
68
69         if (cpu_has(c, X86_FEATURE_TM2) && (l & (1 << 13)))
70                 tm2 = 1;
71
72         if (h & APIC_VECTOR_MASK) {
73                 printk(KERN_DEBUG
74                        "CPU%d: Thermal LVT vector (%#x) already "
75                        "installed\n", cpu, (h & APIC_VECTOR_MASK));
76                 return;
77         }
78
79         h = THERMAL_APIC_VECTOR;
80         h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
81         apic_write_around(APIC_LVTTHMR, h);
82
83         rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
84         wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
85
86         rdmsr(MSR_IA32_MISC_ENABLE, l, h);
87         wrmsr(MSR_IA32_MISC_ENABLE, l | (1 << 3), h);
88
89         l = apic_read(APIC_LVTTHMR);
90         apic_write_around(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
91         printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
92                 cpu, tm2 ? "TM2" : "TM1");
93         return;
94 }
95
96 void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
97 {
98         intel_init_thermal(c);
99 }