aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--arch/x86/kernel/process_32.c5
-rw-r--r--arch/x86/kernel/process_64.c5
-rw-r--r--include/asm-x86/processor.h23
3 files changed, 27 insertions, 6 deletions
diff --git a/arch/x86/kernel/process_32.c b/arch/x86/kernel/process_32.c
index 53bc653ed5ca..3b7a1ddcc0bc 100644
--- a/arch/x86/kernel/process_32.c
+++ b/arch/x86/kernel/process_32.c
@@ -95,7 +95,6 @@ static inline void play_dead(void)
95{ 95{
96 /* This must be done before dead CPU ack */ 96 /* This must be done before dead CPU ack */
97 cpu_exit_clear(); 97 cpu_exit_clear();
98 wbinvd();
99 mb(); 98 mb();
100 /* Ack it */ 99 /* Ack it */
101 __get_cpu_var(cpu_state) = CPU_DEAD; 100 __get_cpu_var(cpu_state) = CPU_DEAD;
@@ -104,8 +103,8 @@ static inline void play_dead(void)
104 * With physical CPU hotplug, we should halt the cpu 103 * With physical CPU hotplug, we should halt the cpu
105 */ 104 */
106 local_irq_disable(); 105 local_irq_disable();
107 while (1) 106 /* mask all interrupts, flush any and all caches, and halt */
108 halt(); 107 wbinvd_halt();
109} 108}
110#else 109#else
111static inline void play_dead(void) 110static inline void play_dead(void)
diff --git a/arch/x86/kernel/process_64.c b/arch/x86/kernel/process_64.c
index 3fb62a7d9a16..71553b664e2a 100644
--- a/arch/x86/kernel/process_64.c
+++ b/arch/x86/kernel/process_64.c
@@ -93,14 +93,13 @@ DECLARE_PER_CPU(int, cpu_state);
93static inline void play_dead(void) 93static inline void play_dead(void)
94{ 94{
95 idle_task_exit(); 95 idle_task_exit();
96 wbinvd();
97 mb(); 96 mb();
98 /* Ack it */ 97 /* Ack it */
99 __get_cpu_var(cpu_state) = CPU_DEAD; 98 __get_cpu_var(cpu_state) = CPU_DEAD;
100 99
101 local_irq_disable(); 100 local_irq_disable();
102 while (1) 101 /* mask all interrupts, flush any and all caches, and halt */
103 halt(); 102 wbinvd_halt();
104} 103}
105#else 104#else
106static inline void play_dead(void) 105static inline void play_dead(void)
diff --git a/include/asm-x86/processor.h b/include/asm-x86/processor.h
index 5f58da401b43..4df3e2f6fb56 100644
--- a/include/asm-x86/processor.h
+++ b/include/asm-x86/processor.h
@@ -728,6 +728,29 @@ extern unsigned long boot_option_idle_override;
728extern unsigned long idle_halt; 728extern unsigned long idle_halt;
729extern unsigned long idle_nomwait; 729extern unsigned long idle_nomwait;
730 730
731/*
732 * on systems with caches, caches must be flashed as the absolute
733 * last instruction before going into a suspended halt. Otherwise,
734 * dirty data can linger in the cache and become stale on resume,
735 * leading to strange errors.
736 *
737 * perform a variety of operations to guarantee that the compiler
738 * will not reorder instructions. wbinvd itself is serializing
739 * so the processor will not reorder.
740 *
741 * Systems without cache can just go into halt.
742 */
743static inline void wbinvd_halt(void)
744{
745 mb();
746 /* check for clflush to determine if wbinvd is legal */
747 if (cpu_has_clflush)
748 asm volatile("cli; wbinvd; 1: hlt; jmp 1b" : : : "memory");
749 else
750 while (1)
751 halt();
752}
753
731extern void enable_sep_cpu(void); 754extern void enable_sep_cpu(void);
732extern int sysenter_setup(void); 755extern int sysenter_setup(void);
733 756