diff options
Diffstat (limited to 'arch/x86_64/kernel/process.c')
-rw-r--r-- | arch/x86_64/kernel/process.c | 52 |
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 | ||
89 | static void __exit_idle(void) | 89 | static 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 | */ |
110 | static void default_idle(void) | 109 | static 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) | |||
131 | static void poll_idle (void) | 128 | static 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 | ||
145 | void cpu_idle_wait(void) | 134 | void 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 | } |
172 | EXPORT_SYMBOL_GPL(cpu_idle_wait); | 163 | EXPORT_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 */ |
256 | static void mwait_idle(void) | 253 | static void mwait_idle(void) |
257 | { | 254 | { |
258 | local_irq_enable(); | 255 | if (!need_resched()) { |
259 | while (!need_resched()) | 256 | __monitor((void *)¤t_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 | ||
263 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) | 267 | void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c) |