[PATCH] Fix TIF_POLLING_NRFLAG in ACPI idle routines

Commit 64c7c8f88559624abdbe12b5da6502e8879f8d28 broke the ACPI C2 and C3
sleep states, because it left TIF_POLLING_NRFLAG active even though
those states do not actually poll the reschedule flag at all. As a
result, the CPU wouldn't get sent an IPI when it was to be woken up, and
would only notice that it had runnable processes on the next timer tick.

Signed-off-by: Linus Torvalds <torvalds@osdl.org>

authored by Nick Piggin and committed by Linus Torvalds 2a298a35 deda4987

+14 -7
+14 -7
drivers/acpi/processor_idle.c
··· 169 169 170 170 static void acpi_safe_halt(void) 171 171 { 172 - int polling = test_thread_flag(TIF_POLLING_NRFLAG); 173 - if (polling) { 174 - clear_thread_flag(TIF_POLLING_NRFLAG); 175 - smp_mb__after_clear_bit(); 176 - } 172 + clear_thread_flag(TIF_POLLING_NRFLAG); 173 + smp_mb__after_clear_bit(); 177 174 if (!need_resched()) 178 175 safe_halt(); 179 - if (polling) 180 - set_thread_flag(TIF_POLLING_NRFLAG); 176 + set_thread_flag(TIF_POLLING_NRFLAG); 181 177 } 182 178 183 179 static atomic_t c3_cpu_count; ··· 291 295 * ------ 292 296 * Invoke the current Cx state to put the processor to sleep. 293 297 */ 298 + if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { 299 + clear_thread_flag(TIF_POLLING_NRFLAG); 300 + smp_mb__after_clear_bit(); 301 + if (need_resched()) { 302 + set_thread_flag(TIF_POLLING_NRFLAG); 303 + return; 304 + } 305 + } 306 + 294 307 switch (cx->type) { 295 308 296 309 case ACPI_STATE_C1: ··· 332 327 t2 = inl(acpi_fadt.xpm_tmr_blk.address); 333 328 /* Re-enable interrupts */ 334 329 local_irq_enable(); 330 + set_thread_flag(TIF_POLLING_NRFLAG); 335 331 /* Compute time (ticks) that we were actually asleep */ 336 332 sleep_ticks = 337 333 ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD; ··· 372 366 373 367 /* Re-enable interrupts */ 374 368 local_irq_enable(); 369 + set_thread_flag(TIF_POLLING_NRFLAG); 375 370 /* Compute time (ticks) that we were actually asleep */ 376 371 sleep_ticks = 377 372 ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;