summary refs log tree commit diff
path: root/drivers
diff options
context:
space:
mode:
authorNick Piggin <nickpiggin@yahoo.com.au>2005-12-02 12:44:19 +1100
committerLinus Torvalds <torvalds@g5.osdl.org>2005-12-02 14:20:21 -0800
commit2a298a35ebe060a6f2b06b20c2a34ea188ddfd37 (patch)
tree226dd2569d657231a3c24d8228467a039ffc6681 /drivers
parentdeda498710e190c7922c2634ed630ee64ce86c05 (diff)
downloadlinux-2a298a35ebe060a6f2b06b20c2a34ea188ddfd37.tar.gz
[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>
Diffstat (limited to 'drivers')
-rw-r--r--drivers/acpi/processor_idle.c21
1 files changed, 14 insertions, 7 deletions
diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c
index 83fd1b6c10c4..acd875e0caca 100644
--- a/drivers/acpi/processor_idle.c
+++ b/drivers/acpi/processor_idle.c
@@ -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;