From 98679ce9f502cd32c26dccd37c5b04643dc904ae Mon Sep 17 00:00:00 2001 From: Greg Kroah-Hartman Date: Fri, 17 Dec 2010 11:45:48 -0800 Subject: [PATCH] .36 patches --- ...line-a-processor-fix-the-legacy-case.patch | 163 ++++++++++++++++++ 1 file changed, 163 insertions(+) create mode 100644 queue-2.6.36/x86-hotplug-use-mwait-to-offline-a-processor-fix-the-legacy-case.patch diff --git a/queue-2.6.36/x86-hotplug-use-mwait-to-offline-a-processor-fix-the-legacy-case.patch b/queue-2.6.36/x86-hotplug-use-mwait-to-offline-a-processor-fix-the-legacy-case.patch new file mode 100644 index 00000000000..cdeb8970e94 --- /dev/null +++ b/queue-2.6.36/x86-hotplug-use-mwait-to-offline-a-processor-fix-the-legacy-case.patch @@ -0,0 +1,163 @@ +From lenb@kernel.org Fri Dec 17 11:26:27 2010 +From: Len Brown +Date: Fri, 10 Dec 2010 23:55:22 -0500 (EST) +Subject: x86, hotplug: Use mwait to offline a processor, fix the legacy case +To: stable@kernel.org +Cc: linux-pm@lists.linux-foundation.org, x86@kernel.org +Message-ID: + + +From: H. Peter Anvin + +upstream ea53069231f9317062910d6e772cca4ce93de8c8 +x86, hotplug: Use mwait to offline a processor, fix the legacy case + +Here included also some small follow-on patches to the same code: + +upstream a68e5c94f7d3dd64fef34dd5d97e365cae4bb42a +x86, hotplug: Move WBINVD back outside the play_dead loop + +upstream ce5f68246bf2385d6174856708d0b746dc378f20 +x86, hotplug: In the MWAIT case of play_dead, CLFLUSH the cache line + +https://bugzilla.kernel.org/show_bug.cgi?id=5471 + +Signed-off-by: H. Peter Anvin +Signed-off-by: Len Brown +Signed-off-by: Greg Kroah-Hartman + +--- + arch/x86/include/asm/processor.h | 23 ---------- + arch/x86/kernel/smpboot.c | 85 ++++++++++++++++++++++++++++++++++++++- + 2 files changed, 84 insertions(+), 24 deletions(-) + +--- a/arch/x86/include/asm/processor.h ++++ b/arch/x86/include/asm/processor.h +@@ -764,29 +764,6 @@ extern unsigned long idle_halt; + extern unsigned long idle_nomwait; + extern bool c1e_detected; + +-/* +- * on systems with caches, caches must be flashed as the absolute +- * last instruction before going into a suspended halt. Otherwise, +- * dirty data can linger in the cache and become stale on resume, +- * leading to strange errors. +- * +- * perform a variety of operations to guarantee that the compiler +- * will not reorder instructions. wbinvd itself is serializing +- * so the processor will not reorder. +- * +- * Systems without cache can just go into halt. +- */ +-static inline void wbinvd_halt(void) +-{ +- mb(); +- /* check for clflush to determine if wbinvd is legal */ +- if (cpu_has_clflush) +- asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory"); +- else +- while (1) +- halt(); +-} +- + extern void enable_sep_cpu(void); + extern int sysenter_setup(void); + +--- a/arch/x86/kernel/smpboot.c ++++ b/arch/x86/kernel/smpboot.c +@@ -1383,11 +1383,94 @@ void play_dead_common(void) + local_irq_disable(); + } + ++#define MWAIT_SUBSTATE_MASK 0xf ++#define MWAIT_SUBSTATE_SIZE 4 ++ ++#define CPUID_MWAIT_LEAF 5 ++#define CPUID5_ECX_EXTENSIONS_SUPPORTED 0x1 ++ ++/* ++ * We need to flush the caches before going to sleep, lest we have ++ * dirty data in our caches when we come back up. ++ */ ++static inline void mwait_play_dead(void) ++{ ++ unsigned int eax, ebx, ecx, edx; ++ unsigned int highest_cstate = 0; ++ unsigned int highest_subcstate = 0; ++ int i; ++ void *mwait_ptr; ++ ++ if (!cpu_has(¤t_cpu_data, X86_FEATURE_MWAIT)) ++ return; ++ if (!cpu_has(¤t_cpu_data, X86_FEATURE_CLFLSH)) ++ return; ++ if (current_cpu_data.cpuid_level < CPUID_MWAIT_LEAF) ++ return; ++ ++ eax = CPUID_MWAIT_LEAF; ++ ecx = 0; ++ native_cpuid(&eax, &ebx, &ecx, &edx); ++ ++ /* ++ * eax will be 0 if EDX enumeration is not valid. ++ * Initialized below to cstate, sub_cstate value when EDX is valid. ++ */ ++ if (!(ecx & CPUID5_ECX_EXTENSIONS_SUPPORTED)) { ++ eax = 0; ++ } else { ++ edx >>= MWAIT_SUBSTATE_SIZE; ++ for (i = 0; i < 7 && edx; i++, edx >>= MWAIT_SUBSTATE_SIZE) { ++ if (edx & MWAIT_SUBSTATE_MASK) { ++ highest_cstate = i; ++ highest_subcstate = edx & MWAIT_SUBSTATE_MASK; ++ } ++ } ++ eax = (highest_cstate << MWAIT_SUBSTATE_SIZE) | ++ (highest_subcstate - 1); ++ } ++ ++ /* ++ * This should be a memory location in a cache line which is ++ * unlikely to be touched by other processors. The actual ++ * content is immaterial as it is not actually modified in any way. ++ */ ++ mwait_ptr = ¤t_thread_info()->flags; ++ ++ wbinvd(); ++ ++ while (1) { ++ /* ++ * The CLFLUSH is a workaround for erratum AAI65 for ++ * the Xeon 7400 series. It's not clear it is actually ++ * needed, but it should be harmless in either case. ++ * The WBINVD is insufficient due to the spurious-wakeup ++ * case where we return around the loop. ++ */ ++ clflush(mwait_ptr); ++ __monitor(mwait_ptr, 0, 0); ++ mb(); ++ __mwait(eax, 0); ++ } ++} ++ ++static inline void hlt_play_dead(void) ++{ ++ if (current_cpu_data.x86 >= 4) ++ wbinvd(); ++ ++ while (1) { ++ native_halt(); ++ } ++} ++ + void native_play_dead(void) + { + play_dead_common(); + tboot_shutdown(TB_SHUTDOWN_WFS); +- wbinvd_halt(); ++ ++ mwait_play_dead(); /* Only returns on failure */ ++ hlt_play_dead(); + } + + #else /* ... !CONFIG_HOTPLUG_CPU */ -- 2.47.3