mce_intel_64.c 2.08 KB
Newer Older
Linus Torvalds's avatar
Linus Torvalds committed
1 2 3 4 5 6 7 8 9
/*
 * Intel specific MCE features.
 * Copyright 2004 Zwane Mwaikambo <zwane@linuxpower.ca>
 */

#include <linux/init.h>
#include <linux/interrupt.h>
#include <linux/percpu.h>
#include <asm/processor.h>
10
#include <asm/apic.h>
Linus Torvalds's avatar
Linus Torvalds committed
11 12 13
#include <asm/msr.h>
#include <asm/mce.h>
#include <asm/hw_irq.h>
14
#include <asm/idle.h>
15
#include <asm/therm_throt.h>
Linus Torvalds's avatar
Linus Torvalds committed
16 17 18

asmlinkage void smp_thermal_interrupt(void)
{
19
	__u64 msr_val;
Linus Torvalds's avatar
Linus Torvalds committed
20 21 22

	ack_APIC_irq();

23
	exit_idle();
Linus Torvalds's avatar
Linus Torvalds committed
24
	irq_enter();
25 26 27 28 29

	rdmsrl(MSR_IA32_THERM_STATUS, msr_val);
	if (therm_throt_process(msr_val & 1))
		mce_log_therm_throt_event(smp_processor_id(), msr_val);

30
	inc_irq_stat(irq_thermal_count);
Linus Torvalds's avatar
Linus Torvalds committed
31 32 33
	irq_exit();
}

34
static void __cpuinit intel_init_thermal(struct cpuinfo_x86 *c)
Linus Torvalds's avatar
Linus Torvalds committed
35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69
{
	u32 l, h;
	int tm2 = 0;
	unsigned int cpu = smp_processor_id();

	if (!cpu_has(c, X86_FEATURE_ACPI))
		return;

	if (!cpu_has(c, X86_FEATURE_ACC))
		return;

	/* first check if TM1 is already enabled by the BIOS, in which
	 * case there might be some SMM goo which handles it, so we can't even
	 * put a handler since it might be delivered via SMI already.
	 */
	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
	h = apic_read(APIC_LVTTHMR);
	if ((l & (1 << 3)) && (h & APIC_DM_SMI)) {
		printk(KERN_DEBUG
		       "CPU%d: Thermal monitoring handled by SMI\n", cpu);
		return;
	}

	if (cpu_has(c, X86_FEATURE_TM2) && (l & (1 << 13)))
		tm2 = 1;

	if (h & APIC_VECTOR_MASK) {
		printk(KERN_DEBUG
		       "CPU%d: Thermal LVT vector (%#x) already "
		       "installed\n", cpu, (h & APIC_VECTOR_MASK));
		return;
	}

	h = THERMAL_APIC_VECTOR;
	h |= (APIC_DM_FIXED | APIC_LVT_MASKED);
70
	apic_write(APIC_LVTTHMR, h);
Linus Torvalds's avatar
Linus Torvalds committed
71 72 73 74 75 76 77 78

	rdmsr(MSR_IA32_THERM_INTERRUPT, l, h);
	wrmsr(MSR_IA32_THERM_INTERRUPT, l | 0x03, h);

	rdmsr(MSR_IA32_MISC_ENABLE, l, h);
	wrmsr(MSR_IA32_MISC_ENABLE, l | (1 << 3), h);

	l = apic_read(APIC_LVTTHMR);
79
	apic_write(APIC_LVTTHMR, l & ~APIC_LVT_MASKED);
Linus Torvalds's avatar
Linus Torvalds committed
80 81
	printk(KERN_INFO "CPU%d: Thermal monitoring enabled (%s)\n",
		cpu, tm2 ? "TM2" : "TM1");
82 83 84

	/* enable thermal throttle processing */
	atomic_set(&therm_throt_en, 1);
Linus Torvalds's avatar
Linus Torvalds committed
85 86 87
	return;
}

88
void __cpuinit mce_intel_feature_init(struct cpuinfo_x86 *c)
Linus Torvalds's avatar
Linus Torvalds committed
89 90 91
{
	intel_init_thermal(c);
}