Pull asus into release branch
[pandora-kernel.git] / arch / x86_64 / kernel / process.c
index 0b7b4ca..d8d5ccc 100644 (file)
@@ -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.
@@ -127,6 +131,7 @@ static void default_idle(void)
  */
 static void poll_idle (void)
 {
+       local_irq_enable();
        cpu_relax();
 }
 
@@ -208,6 +213,12 @@ void cpu_idle (void)
                                idle = default_idle;
                        if (cpu_is_offline(smp_processor_id()))
                                play_dead();
+                       /*
+                        * Idle routines should keep interrupts disabled
+                        * from here on, until they go to idle.
+                        * Otherwise, idle callbacks can misfire.
+                        */
+                       local_irq_disable();
                        enter_idle();
                        idle();
                        /* In many cases the interrupt that ended idle
@@ -245,8 +256,16 @@ void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 /* Default MONITOR/MWAIT with no hints, used for default C1 state */
 static void mwait_idle(void)
 {
-       local_irq_enable();
-       mwait_idle_with_hints(0,0);
+       if (!need_resched()) {
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __sti_mwait(0, 0);
+               else
+                       local_irq_enable();
+       } else {
+               local_irq_enable();
+       }
 }
 
 void __cpuinit select_idle_routine(const struct cpuinfo_x86 *c)
@@ -363,14 +382,17 @@ void exit_thread(void)
 void flush_thread(void)
 {
        struct task_struct *tsk = current;
-       struct thread_info *t = current_thread_info();
 
-       if (t->flags & _TIF_ABI_PENDING) {
-               t->flags ^= (_TIF_ABI_PENDING | _TIF_IA32);
-               if (t->flags & _TIF_IA32)
+       if (test_tsk_thread_flag(tsk, TIF_ABI_PENDING)) {
+               clear_tsk_thread_flag(tsk, TIF_ABI_PENDING);
+               if (test_tsk_thread_flag(tsk, TIF_IA32)) {
+                       clear_tsk_thread_flag(tsk, TIF_IA32);
+               } else {
+                       set_tsk_thread_flag(tsk, TIF_IA32);
                        current_thread_info()->status |= TS_COMPAT;
+               }
        }
-       t->flags &= ~_TIF_DEBUG;
+       clear_tsk_thread_flag(tsk, TIF_DEBUG);
 
        tsk->thread.debugreg0 = 0;
        tsk->thread.debugreg1 = 0;