[PATCH] Fix TIF_POLLING_NRFLAG in ACPI idle routines
authorNick Piggin <nickpiggin@yahoo.com.au>
Fri, 2 Dec 2005 01:44:19 +0000 (12:44 +1100)
committerLinus Torvalds <torvalds@g5.osdl.org>
Fri, 2 Dec 2005 22:20:21 +0000 (14:20 -0800)
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>
drivers/acpi/processor_idle.c

index 83fd1b6c10c41e7ddb62c271661523ef3affafc9..acd875e0cacac3912a0c83a8f6549b343fd79176 100644 (file)
@@ -169,15 +169,11 @@ acpi_processor_power_activate(struct acpi_processor *pr,
 
 static void acpi_safe_halt(void)
 {
-       int polling = test_thread_flag(TIF_POLLING_NRFLAG);
-       if (polling) {
-               clear_thread_flag(TIF_POLLING_NRFLAG);
-               smp_mb__after_clear_bit();
-       }
+       clear_thread_flag(TIF_POLLING_NRFLAG);
+       smp_mb__after_clear_bit();
        if (!need_resched())
                safe_halt();
-       if (polling)
-               set_thread_flag(TIF_POLLING_NRFLAG);
+       set_thread_flag(TIF_POLLING_NRFLAG);
 }
 
 static atomic_t c3_cpu_count;
@@ -295,6 +291,15 @@ static void acpi_processor_idle(void)
         * ------
         * Invoke the current Cx state to put the processor to sleep.
         */
+       if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) {
+               clear_thread_flag(TIF_POLLING_NRFLAG);
+               smp_mb__after_clear_bit();
+               if (need_resched()) {
+                       set_thread_flag(TIF_POLLING_NRFLAG);
+                       return;
+               }
+       }
+
        switch (cx->type) {
 
        case ACPI_STATE_C1:
@@ -327,6 +332,7 @@ static void acpi_processor_idle(void)
                t2 = inl(acpi_fadt.xpm_tmr_blk.address);
                /* Re-enable interrupts */
                local_irq_enable();
+               set_thread_flag(TIF_POLLING_NRFLAG);
                /* Compute time (ticks) that we were actually asleep */
                sleep_ticks =
                    ticks_elapsed(t1, t2) - cx->latency_ticks - C2_OVERHEAD;
@@ -366,6 +372,7 @@ static void acpi_processor_idle(void)
 
                /* Re-enable interrupts */
                local_irq_enable();
+               set_thread_flag(TIF_POLLING_NRFLAG);
                /* Compute time (ticks) that we were actually asleep */
                sleep_ticks =
                    ticks_elapsed(t1, t2) - cx->latency_ticks - C3_OVERHEAD;