aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86_64/kernel/process.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r--arch/x86_64/kernel/process.c52
1 files changed, 28 insertions, 24 deletions
diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c
index 49f7fac6229e..a418ee4c8c62 100644
--- a/arch/x86_64/kernel/process.c
+++ b/arch/x86_64/kernel/process.c
@@ -88,9 +88,8 @@ void enter_idle(void)
88 88
89static void __exit_idle(void) 89static void __exit_idle(void)
90{ 90{
91 if (read_pda(isidle) == 0) 91 if (test_and_clear_bit_pda(0, isidle) == 0)
92 return; 92 return;
93 write_pda(isidle, 0);
94 atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL); 93 atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
95} 94}
96 95
@@ -109,17 +108,15 @@ void exit_idle(void)
109 */ 108 */
110static void default_idle(void) 109static void default_idle(void)
111{ 110{
112 local_irq_enable();
113
114 current_thread_info()->status &= ~TS_POLLING; 111 current_thread_info()->status &= ~TS_POLLING;
115 smp_mb__after_clear_bit(); 112 smp_mb__after_clear_bit();
116 while (!need_resched()) { 113 local_irq_disable();
117 local_irq_disable(); 114 if (!need_resched()) {
118 if (!need_resched()) 115 /* Enables interrupts one instruction before HLT.
119 safe_halt(); 116 x86 special cases this so there is no race. */
120 else 117 safe_halt();
121 local_irq_enable(); 118 } else
122 } 119 local_irq_enable();
123 current_thread_info()->status |= TS_POLLING; 120 current_thread_info()->status |= TS_POLLING;
124} 121}
125 122
@@ -131,21 +128,13 @@ static void default_idle(void)
131static void poll_idle (void) 128static void poll_idle (void)
132{ 129{
133 local_irq_enable(); 130 local_irq_enable();
134 131 cpu_relax();
135 asm volatile(
136 "2:"
137 "testl %0,%1;"
138 "rep; nop;"
139 "je 2b;"
140 : :
141 "i" (_TIF_NEED_RESCHED),
142 "m" (current_thread_info()->flags));
143} 132}
144 133
145void cpu_idle_wait(void) 134void cpu_idle_wait(void)
146{ 135{
147 unsigned int cpu, this_cpu = get_cpu(); 136 unsigned int cpu, this_cpu = get_cpu();
148 cpumask_t map; 137 cpumask_t map, tmp = current->cpus_allowed;
149 138
150 set_cpus_allowed(current, cpumask_of_cpu(this_cpu)); 139 set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
151 put_cpu(); 140 put_cpu();
@@ -168,6 +157,8 @@ void cpu_idle_wait(void)
168 } 157 }
169 cpus_and(map, map, cpu_online_map); 158 cpus_and(map, map, cpu_online_map);
170 } while (!cpus_empty(map)); 159 } while (!cpus_empty(map));
160
161 set_cpus_allowed(current, tmp);
171} 162}
172EXPORT_SYMBOL_GPL(cpu_idle_wait); 163EXPORT_SYMBOL_GPL(cpu_idle_wait);
173 164
@@ -218,6 +209,12 @@ void cpu_idle (void)
218 idle = default_idle; 209 idle = default_idle;
219 if (cpu_is_offline(smp_processor_id())) 210 if (cpu_is_offline(smp_processor_id()))
220 play_dead(); 211 play_dead();
212 /*
213 * Idle routines should keep interrupts disabled
214 * from here on, until they go to idle.
215 * Otherwise, idle callbacks can misfire.
216 */
217 local_irq_disable();
221 enter_idle(); 218 enter_idle();
222 idle(); 219 idle();
223 /* In many cases the interrupt that ended idle 220 /* In many cases the interrupt that ended idle
@@ -255,9 +252,16 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
255/* Default MONITOR/MWAIT with no hints, used for default C1 state */ 252/* Default MONITOR/MWAIT with no hints, used for default C1 state */
256static void mwait_idle(void) 253static void mwait_idle(void)
257{ 254{
258 local_irq_enable(); 255 if (!need_resched()) {
259 while (!need_resched()) 256 __monitor((void *)&current_thread_info()->flags, 0, 0);
260 mwait_idle_with_hints(0,0); 257 smp_mb();
258 if (!need_resched())
259 __sti_mwait(0, 0);
260 else
261 local_irq_enable();
262 } else {
263 local_irq_enable();
264 }
261} 265}
262 266
263void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) 267void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)