aboutsummaryrefslogtreecommitdiffstats
path: root/arch
diff options
context:
space:
mode:
authorYong Wang <yong.y.wang@linux.intel.com>2009-11-09 20:38:24 -0500
committerIngo Molnar <mingo@elte.hu>2009-11-09 23:57:55 -0500
commita2202aa29289db64ca7988b12343158b67b27f10 (patch)
treee84a34b587b07243b3d3557795f8e3fa03302fee /arch
parentb33a6363649f0ff83ec81597ea7fe7e688f973cb (diff)
x86: Under BIOS control, restore AP's APIC_LVTTHMR to the BSP value
On platforms where the BIOS handles the thermal monitor interrupt, APIC_LVTTHMR on each logical CPU is programmed to generate a SMI and OS must not touch it. Unfortunately AP bringup sequence using INIT-SIPI-SIPI clears all the LVT entries except the mask bit. Essentially this results in all LVT entries including the thermal monitoring interrupt set to masked (clearing the bios programmed value for APIC_LVTTHMR). And this leads to kernel take over the thermal monitoring interrupt on AP's but not on BSP (leaving the bios programmed value only on BSP). As a result of this, we have seen system hangs when the thermal monitoring interrupt is generated. Fix this by reading the initial value of thermal LVT entry on BSP and if bios has taken over the control, then program the same value on all AP's and leave the thermal monitoring interrupt control on all the logical cpu's to the bios. Signed-off-by: Yong Wang <yong.y.wang@intel.com> Reviewed-by: Suresh Siddha <suresh.b.siddha@intel.com> Cc: Borislav Petkov <borislav.petkov@amd.com> Cc: Arjan van de Ven <arjan@infradead.org> LKML-Reference: <20091110013824.GA24940@ywang-moblin2.bj.intel.com> Signed-off-by: Ingo Molnar <mingo@elte.hu> Cc: stable@kernel.org
Diffstat (limited to 'arch')
-rw-r--r--arch/x86/include/asm/mce.h9
-rw-r--r--arch/x86/kernel/cpu/common.c2
-rw-r--r--arch/x86/kernel/cpu/mcheck/mce.c5
-rw-r--r--arch/x86/kernel/cpu/mcheck/therm_throt.c29
-rw-r--r--arch/x86/kernel/setup.c3
5 files changed, 43 insertions, 5 deletions
diff --git a/arch/x86/include/asm/mce.h b/arch/x86/include/asm/mce.h
index 161485da6838..858baa061cfc 100644
--- a/arch/x86/include/asm/mce.h
+++ b/arch/x86/include/asm/mce.h
@@ -120,8 +120,10 @@ extern int mce_disabled;
120extern int mce_p5_enabled; 120extern int mce_p5_enabled;
121 121
122#ifdef CONFIG_X86_MCE 122#ifdef CONFIG_X86_MCE
123int mcheck_init(void);
123void mcheck_cpu_init(struct cpuinfo_x86 *c); 124void mcheck_cpu_init(struct cpuinfo_x86 *c);
124#else 125#else
126static inline int mcheck_init(void) { return 0; }
125static inline void mcheck_cpu_init(struct cpuinfo_x86 *c) {} 127static inline void mcheck_cpu_init(struct cpuinfo_x86 *c) {}
126#endif 128#endif
127 129
@@ -215,5 +217,12 @@ extern void (*threshold_cpu_callback)(unsigned long action, unsigned int cpu);
215void intel_init_thermal(struct cpuinfo_x86 *c); 217void intel_init_thermal(struct cpuinfo_x86 *c);
216 218
217void mce_log_therm_throt_event(__u64 status); 219void mce_log_therm_throt_event(__u64 status);
220
221#ifdef CONFIG_X86_THERMAL_VECTOR
222extern void mcheck_intel_therm_init(void);
223#else
224static inline void mcheck_intel_therm_init(void) { }
225#endif
226
218#endif /* __KERNEL__ */ 227#endif /* __KERNEL__ */
219#endif /* _ASM_X86_MCE_H */ 228#endif /* _ASM_X86_MCE_H */
diff --git a/arch/x86/kernel/cpu/common.c b/arch/x86/kernel/cpu/common.c
index 4df69a38be57..9053be5d95cd 100644
--- a/arch/x86/kernel/cpu/common.c
+++ b/arch/x86/kernel/cpu/common.c
@@ -837,10 +837,8 @@ static void __cpuinit identify_cpu(struct cpuinfo_x86 *c)
837 boot_cpu_data.x86_capability[i] &= c->x86_capability[i]; 837 boot_cpu_data.x86_capability[i] &= c->x86_capability[i];
838 } 838 }
839 839
840#ifdef CONFIG_X86_MCE
841 /* Init Machine Check Exception if available. */ 840 /* Init Machine Check Exception if available. */
842 mcheck_cpu_init(c); 841 mcheck_cpu_init(c);
843#endif
844 842
845 select_idle_routine(c); 843 select_idle_routine(c);
846 844
diff --git a/arch/x86/kernel/cpu/mcheck/mce.c b/arch/x86/kernel/cpu/mcheck/mce.c
index 80801705edd7..0d4102031a4c 100644
--- a/arch/x86/kernel/cpu/mcheck/mce.c
+++ b/arch/x86/kernel/cpu/mcheck/mce.c
@@ -1655,13 +1655,14 @@ static int __init mcheck_enable(char *str)
1655} 1655}
1656__setup("mce", mcheck_enable); 1656__setup("mce", mcheck_enable);
1657 1657
1658static int __init mcheck_init(void) 1658int __init mcheck_init(void)
1659{ 1659{
1660 atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb); 1660 atomic_notifier_chain_register(&x86_mce_decoder_chain, &mce_dec_nb);
1661 1661
1662 mcheck_intel_therm_init();
1663
1662 return 0; 1664 return 0;
1663} 1665}
1664early_initcall(mcheck_init);
1665 1666
1666/* 1667/*
1667 * Sysfs support 1668 * Sysfs support
diff --git a/arch/x86/kernel/cpu/mcheck/therm_throt.c b/arch/x86/kernel/cpu/mcheck/therm_throt.c
index b3a1dba75330..7f3cf36ed124 100644
--- a/arch/x86/kernel/cpu/mcheck/therm_throt.c
+++ b/arch/x86/kernel/cpu/mcheck/therm_throt.c
@@ -49,6 +49,8 @@ static DEFINE_PER_CPU(struct thermal_state, thermal_state);
49 49
50static atomic_t therm_throt_en = ATOMIC_INIT(0); 50static atomic_t therm_throt_en = ATOMIC_INIT(0);
51 51
52static u32 lvtthmr_init __read_mostly;
53
52#ifdef CONFIG_SYSFS 54#ifdef CONFIG_SYSFS
53#define define_therm_throt_sysdev_one_ro(_name) \ 55#define define_therm_throt_sysdev_one_ro(_name) \
54 static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL) 56 static SYSDEV_ATTR(_name, 0444, therm_throt_sysdev_show_##_name, NULL)
@@ -254,6 +256,18 @@ asmlinkage void smp_thermal_interrupt(struct pt_regs *regs)
254 ack_APIC_irq(); 256 ack_APIC_irq();
255} 257}
256 258
259void mcheck_intel_therm_init(void)
260{
261 /*
262 * This function is only called on boot CPU. Save the init thermal
263 * LVT value on BSP and use that value to restore APs' thermal LVT
264 * entry BIOS programmed later
265 */
266 if (cpu_has(&boot_cpu_data, X86_FEATURE_ACPI) &&
267 cpu_has(&boot_cpu_data, X86_FEATURE_ACC))
268 lvtthmr_init = apic_read(APIC_LVTTHMR);
269}
270
257void intel_init_thermal(struct cpuinfo_x86 *c) 271void intel_init_thermal(struct cpuinfo_x86 *c)
258{ 272{
259 unsigned int cpu = smp_processor_id(); 273 unsigned int cpu = smp_processor_id();
@@ -270,7 +284,20 @@ void intel_init_thermal(struct cpuinfo_x86 *c)
270 * since it might be delivered via SMI already: 284 * since it might be delivered via SMI already:
271 */ 285 */
272 rdmsr(MSR_IA32_MISC_ENABLE, l, h); 286 rdmsr(MSR_IA32_MISC_ENABLE, l, h);
273 h = apic_read(APIC_LVTTHMR); 287
288 /*
289 * The initial value of thermal LVT entries on all APs always reads
290 * 0x10000 because APs are woken up by BSP issuing INIT-SIPI-SIPI
291 * sequence to them and LVT registers are reset to 0s except for
292 * the mask bits which are set to 1s when APs receive INIT IPI.
293 * Always restore the value that BIOS has programmed on AP based on
294 * BSP's info we saved since BIOS is always setting the same value
295 * for all threads/cores
296 */
297 apic_write(APIC_LVTTHMR, lvtthmr_init);
298
299 h = lvtthmr_init;
300
274 if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) { 301 if ((l & MSR_IA32_MISC_ENABLE_TM1) && (h & APIC_DM_SMI)) {
275 printk(KERN_DEBUG 302 printk(KERN_DEBUG
276 "CPU%d: Thermal monitoring handled by SMI\n", cpu); 303 "CPU%d: Thermal monitoring handled by SMI\n", cpu);
diff --git a/arch/x86/kernel/setup.c b/arch/x86/kernel/setup.c
index e09f0e2c14b5..179c1f2aa457 100644
--- a/arch/x86/kernel/setup.c
+++ b/arch/x86/kernel/setup.c
@@ -109,6 +109,7 @@
109#ifdef CONFIG_X86_64 109#ifdef CONFIG_X86_64
110#include <asm/numa_64.h> 110#include <asm/numa_64.h>
111#endif 111#endif
112#include <asm/mce.h>
112 113
113/* 114/*
114 * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries. 115 * end_pfn only includes RAM, while max_pfn_mapped includes all e820 entries.
@@ -1024,6 +1025,8 @@ void __init setup_arch(char **cmdline_p)
1024#endif 1025#endif
1025#endif 1026#endif
1026 x86_init.oem.banner(); 1027 x86_init.oem.banner();
1028
1029 mcheck_init();
1027} 1030}
1028 1031
1029#ifdef CONFIG_X86_32 1032#ifdef CONFIG_X86_32