2 * Intel specific MCE features.
3 * Copyright 2004 Zwane Mwaikambo <zwane@linuxpower.ca>
6 #include <linux/init.h>
7 #include <linux/interrupt.h>
8 #include <linux/percpu.h>
9 #include <asm/processor.h>
12 #include <asm/hw_irq.h>
15 static DEFINE_PER_CPU(unsigned long, next_check);
17 asmlinkage void smp_thermal_interrupt(void)
25 if (time_before(jiffies, __get_cpu_var(next_check)))
28 __get_cpu_var(next_check) = jiffies + HZ*300;
29 memset(&m, 0, sizeof(m));
30 m.cpu = smp_processor_id();
31 m.bank = MCE_THERMAL_BANK;
33 rdmsrl(MSR_IA32_THERM_STATUS, m.status);
36 "CPU%d: Temperature above threshold, cpu clock throttled\n", m.cpu);
37 add_taint(TAINT_MACHINE_CHECK);
39 printk(KERN_EMERG "CPU%d: Temperature/speed normal\n", m.cpu);
47 static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
51 unsigned int cpu = smp_processor_id();
53 if (!cpu_has(c, X86_FEATURE_ACPI))
56 if (!cpu_has(c, X86_FEATURE_ACC))
59 /* first check if TM1 is already enabled by the BIOS, in which
60 * case there might be some SMM goo which handles it, so we can't even
61 * put a handler since it might be delivered via SMI already.
63 rdmsr(MSR_IA32_MISC_ENABLE, l, h);
64 h = apic_read(APIC_LVTTHMR);
65 if ((l & (1 << 3)) && (h & APIC_DM_SMI)) {
67 "CPU%d: Thermal monitoring handled by SMI\n", cpu);
71 if (cpu_has(c, X86_FEATURE_TM2) && (l & (1 << 13)))
74 if (h & APIC_VECTOR_MASK) {
76 "CPU%d: Thermal LVT vector (%#x) already "
77 "installed\n", cpu, (h & APIC_VECTOR_MASK));
81 h = THERMAL_APIC_VECTOR;
82 h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
83 apic_write(APIC_LVTTHMR, h);
85 rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
86 wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);
88 rdmsr(MSR_IA32_MISC_ENABLE, l, h);
89 wrmsr(MSR_IA32_MISC_ENABLE, l | (1 << 3), h);
91 l = apic_read(APIC_LVTTHMR);
92 apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
93 printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
94 cpu, tm2 ? "TM2" : "TM1");
98 void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
100 intel_init_thermal(c);