]> git.ipfire.org Git - thirdparty/kernel/stable-queue.git/commitdiff
.36 patches
authorGreg Kroah-Hartman <gregkh@suse.de>
Fri, 17 Dec 2010 19:45:48 +0000 (11:45 -0800)
committerGreg Kroah-Hartman <gregkh@suse.de>
Fri, 17 Dec 2010 19:45:48 +0000 (11:45 -0800)
queue-2.6.36/x86-hotplug-use-mwait-to-offline-a-processor-fix-the-legacy-case.patch [new file with mode: 0644]

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 (file)
index 0000000..cdeb897
--- /dev/null
@@ -0,0 +1,163 @@
+From lenb@kernel.org  Fri Dec 17 11:26:27 2010
+From: Len Brown <lenb@kernel.org>
+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: <alpine.LFD.2.00.1012102353270.7564@x980>
+
+
+From: H. Peter Anvin <hpa@linux.intel.com>
+
+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 <hpa@linux.intel.com>
+Signed-off-by: Len Brown <len.brown@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@suse.de>
+
+---
+ 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(&current_cpu_data, X86_FEATURE_MWAIT))
++              return;
++      if (!cpu_has(&current_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 = &current_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 */