diff --git a/arch/i386/kernel/apm.c b/arch/i386/kernel/apm.c index b75cff25de4b105b7c4c510d4de9752f053c2488..199016927541871f4dc18a4d0e746e03873ba700 100644 --- a/arch/i386/kernel/apm.c +++ b/arch/i386/kernel/apm.c @@ -785,7 +785,11 @@ static int apm_do_idle(void) polling = !!(current_thread_info()->status & TS_POLLING); if (polling) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); } if (!need_resched()) { idled = 1; diff --git a/arch/i386/kernel/process.c b/arch/i386/kernel/process.c index 99308510a17c7fdab49f6a90a1f09e9f9917cf37..c641056233a60a2bffaff12edae8773018019945 100644 --- a/arch/i386/kernel/process.c +++ b/arch/i386/kernel/process.c @@ -102,7 +102,12 @@ void default_idle(void) { if (!hlt_counter && boot_cpu_data.hlt_works_ok) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); + local_irq_disable(); if (!need_resched()) safe_halt(); /* enables interrupts racelessly */ diff --git a/arch/ia64/kernel/process.c b/arch/ia64/kernel/process.c index 51922b98086afb1919a174772206263ab9519a39..17685abaf49642659b1598f8d5474168c05bc19e 100644 --- a/arch/ia64/kernel/process.c +++ b/arch/ia64/kernel/process.c @@ -268,10 +268,16 @@ cpu_idle (void) /* endless idle loop with no priority at all */ while (1) { - if (can_do_pal_halt) + if (can_do_pal_halt) { current_thread_info()->status &= ~TS_POLLING; - else + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); + } else { current_thread_info()->status |= TS_POLLING; + } if (!need_resched()) { void (*idle)(void); diff --git a/arch/x86_64/kernel/process.c b/arch/x86_64/kernel/process.c index a418ee4c8c62a0d14102b22939dfa8c5b16d0f79..cbbc6adc1a92004c902954f10777528f6b964178 100644 --- a/arch/x86_64/kernel/process.c +++ b/arch/x86_64/kernel/process.c @@ -109,7 +109,11 @@ void exit_idle(void) static void default_idle(void) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); local_irq_disable(); if (!need_resched()) { /* Enables interrupts one instruction before HLT. diff --git a/drivers/acpi/processor_idle.c b/drivers/acpi/processor_idle.c index 65b3f056ad895a7d0f524f7412ff861ce9298649..6dac6050bb5a1b24602810621831ecd75ae70900 100644 --- a/drivers/acpi/processor_idle.c +++ b/drivers/acpi/processor_idle.c @@ -211,7 +211,11 @@ acpi_processor_power_activate(struct acpi_processor *pr, static void acpi_safe_halt(void) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); if (!need_resched()) safe_halt(); current_thread_info()->status |= TS_POLLING; @@ -345,7 +349,11 @@ static void acpi_processor_idle(void) */ if (cx->type == ACPI_STATE_C2 || cx->type == ACPI_STATE_C3) { current_thread_info()->status &= ~TS_POLLING; - smp_mb__after_clear_bit(); + /* + * TS_POLLING-cleared state must be visible before we + * test NEED_RESCHED: + */ + smp_mb(); if (need_resched()) { current_thread_info()->status |= TS_POLLING; local_irq_enable();