diff options
Diffstat (limited to 'arch/x86/kernel/cpu/mcheck/mce_intel_64.c')
-rw-r--r-- | arch/x86/kernel/cpu/mcheck/mce_intel_64.c | 90 |
1 files changed, 90 insertions, 0 deletions
diff --git a/arch/x86/kernel/cpu/mcheck/mce_intel_64.c b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c new file mode 100644 index 000000000000..c17eaf5dd6dd --- /dev/null +++ b/arch/x86/kernel/cpu/mcheck/mce_intel_64.c | |||
@@ -0,0 +1,90 @@ | |||
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 | } | ||