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 16asmlinkage 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 32static 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 86void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c) 87{ 88 intel_init_thermal(c); 89} 90