diff options
Diffstat (limited to 'arch/i386/kernel')
-rw-r--r-- | arch/i386/kernel/cpu/mcheck/Makefile | 2 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/mcheck/p4.c | 23 | ||||
-rw-r--r-- | arch/i386/kernel/cpu/mcheck/therm_throt.c | 58 |
3 files changed, 65 insertions, 18 deletions
diff --git a/arch/i386/kernel/cpu/mcheck/Makefile b/arch/i386/kernel/cpu/mcheck/Makefile index 30808f3d6715..f1ebe1c1c17a 100644 --- a/arch/i386/kernel/cpu/mcheck/Makefile +++ b/arch/i386/kernel/cpu/mcheck/Makefile | |||
@@ -1,2 +1,2 @@ | |||
1 | obj-y = mce.o k7.o p4.o p5.o p6.o winchip.o | 1 | obj-y = mce.o k7.o p4.o p5.o p6.o winchip.o therm_throt.o |
2 | obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o | 2 | obj-$(CONFIG_X86_MCE_NONFATAL) += non-fatal.o |
diff --git a/arch/i386/kernel/cpu/mcheck/p4.c b/arch/i386/kernel/cpu/mcheck/p4.c index b95f1b3d53aa..d83a669d376f 100644 --- a/arch/i386/kernel/cpu/mcheck/p4.c +++ b/arch/i386/kernel/cpu/mcheck/p4.c | |||
@@ -13,6 +13,8 @@ | |||
13 | #include <asm/msr.h> | 13 | #include <asm/msr.h> |
14 | #include <asm/apic.h> | 14 | #include <asm/apic.h> |
15 | 15 | ||
16 | #include <asm/therm_throt.h> | ||
17 | |||
16 | #include "mce.h" | 18 | #include "mce.h" |
17 | 19 | ||
18 | /* as supported by the P4/Xeon family */ | 20 | /* as supported by the P4/Xeon family */ |
@@ -44,25 +46,12 @@ static void unexpected_thermal_interrupt(struct pt_regs *regs) | |||
44 | /* P4/Xeon Thermal transition interrupt handler */ | 46 | /* P4/Xeon Thermal transition interrupt handler */ |
45 | static void intel_thermal_interrupt(struct pt_regs *regs) | 47 | static void intel_thermal_interrupt(struct pt_regs *regs) |
46 | { | 48 | { |
47 | u32 l, h; | 49 | __u64 msr_val; |
48 | unsigned int cpu = smp_processor_id(); | ||
49 | static unsigned long next[NR_CPUS]; | ||
50 | 50 | ||
51 | ack_APIC_irq(); | 51 | ack_APIC_irq(); |
52 | 52 | ||
53 | if (time_after(next[cpu], jiffies)) | 53 | rdmsrl(MSR_IA32_THERM_STATUS, msr_val); |
54 | return; | 54 | therm_throt_process(msr_val & 0x1); |
55 | |||
56 | next[cpu] = jiffies + HZ*5; | ||
57 | rdmsr(MSR_IA32_THERM_STATUS, l, h); | ||
58 | if (l & 0x1) { | ||
59 | printk(KERN_EMERG "CPU%d: Temperature above threshold\n", cpu); | ||
60 | printk(KERN_EMERG "CPU%d: Running in modulated clock mode\n", | ||
61 | cpu); | ||
62 | add_taint(TAINT_MACHINE_CHECK); | ||
63 | } else { | ||
64 | printk(KERN_INFO "CPU%d: Temperature/speed normal\n", cpu); | ||
65 | } | ||
66 | } | 55 | } |
67 | 56 | ||
68 | /* Thermal interrupt handler for this CPU setup */ | 57 | /* Thermal interrupt handler for this CPU setup */ |
@@ -122,7 +111,7 @@ static void intel_init_thermal(struct cpuinfo_x86 *c) | |||
122 | 111 | ||
123 | rdmsr (MSR_IA32_MISC_ENABLE, l, h); | 112 | rdmsr (MSR_IA32_MISC_ENABLE, l, h); |
124 | wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h); | 113 | wrmsr (MSR_IA32_MISC_ENABLE, l | (1<<3), h); |
125 | 114 | ||
126 | l = apic_read (APIC_LVTTHMR); | 115 | l = apic_read (APIC_LVTTHMR); |
127 | apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED); | 116 | apic_write_around (APIC_LVTTHMR, l & ~APIC_LVT_MASKED); |
128 | printk (KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu); | 117 | printk (KERN_INFO "CPU%d: Thermal monitoring enabled\n", cpu); |
diff --git a/arch/i386/kernel/cpu/mcheck/therm_throt.c b/arch/i386/kernel/cpu/mcheck/therm_throt.c new file mode 100644 index 000000000000..85eba00d680e --- /dev/null +++ b/arch/i386/kernel/cpu/mcheck/therm_throt.c | |||
@@ -0,0 +1,58 @@ | |||
1 | /* | ||
2 | * linux/arch/i386/kerne/cpu/mcheck/therm_throt.c | ||
3 | * | ||
4 | * Thermal throttle event support code. | ||
5 | * | ||
6 | * Author: Dmitriy Zavin (dmitriyz@google.com) | ||
7 | * | ||
8 | * Credits: Adapted from Zwane Mwaikambo's original code in mce_intel.c. | ||
9 | * | ||
10 | */ | ||
11 | |||
12 | #include <linux/percpu.h> | ||
13 | #include <linux/cpu.h> | ||
14 | #include <asm/cpu.h> | ||
15 | #include <linux/notifier.h> | ||
16 | #include <asm/therm_throt.h> | ||
17 | |||
18 | /* How long to wait between reporting thermal events */ | ||
19 | #define CHECK_INTERVAL (300 * HZ) | ||
20 | |||
21 | static DEFINE_PER_CPU(unsigned long, next_check); | ||
22 | |||
23 | /*** | ||
24 | * therm_throt_process - Process thermal throttling event | ||
25 | * @curr: Whether the condition is current or not (boolean), since the | ||
26 | * thermal interrupt normally gets called both when the thermal | ||
27 | * event begins and once the event has ended. | ||
28 | * | ||
29 | * This function is normally called by the thermal interrupt after the | ||
30 | * IRQ has been acknowledged. | ||
31 | * | ||
32 | * It will take care of rate limiting and printing messages to the syslog. | ||
33 | * | ||
34 | * Returns: 0 : Event should NOT be further logged, i.e. still in | ||
35 | * "timeout" from previous log message. | ||
36 | * 1 : Event should be logged further, and a message has been | ||
37 | * printed to the syslog. | ||
38 | */ | ||
39 | int therm_throt_process(int curr) | ||
40 | { | ||
41 | unsigned int cpu = smp_processor_id(); | ||
42 | |||
43 | if (time_before(jiffies, __get_cpu_var(next_check))) | ||
44 | return 0; | ||
45 | |||
46 | __get_cpu_var(next_check) = jiffies + CHECK_INTERVAL; | ||
47 | |||
48 | /* if we just entered the thermal event */ | ||
49 | if (curr) { | ||
50 | printk(KERN_CRIT "CPU%d: Temperature above threshold, " | ||
51 | "cpu clock throttled\n", cpu); | ||
52 | add_taint(TAINT_MACHINE_CHECK); | ||
53 | } else { | ||
54 | printk(KERN_CRIT "CPU%d: Temperature/speed normal\n", cpu); | ||
55 | } | ||
56 | |||
57 | return 1; | ||
58 | } | ||