Merge branch 'drm-patches' of git://git.kernel.org/pub/scm/linux/kernel/git/airlied...
[pandora-kernel.git] / arch / x86_64 / kernel / process.c
index 5e95b25..a418ee4 100644 (file)
@@ -88,9 +88,8 @@ void enter_idle(void)
 
 static void __exit_idle(void)
 {
-       if (read_pda(isidle) == 0)
+       if (test_and_clear_bit_pda(0, isidle) == 0)
                return;
-       write_pda(isidle, 0);
        atomic_notifier_call_chain(&idle_notifier, IDLE_END, NULL);
 }
 
@@ -109,17 +108,15 @@ void exit_idle(void)
  */
 static void default_idle(void)
 {
-       local_irq_enable();
-
        current_thread_info()->status &= ~TS_POLLING;
        smp_mb__after_clear_bit();
-       while (!need_resched()) {
-               local_irq_disable();
-               if (!need_resched())
-                       safe_halt();
-               else
-                       local_irq_enable();
-       }
+       local_irq_disable();
+       if (!need_resched()) {
+               /* Enables interrupts one instruction before HLT.
+                  x86 special cases this so there is no race. */
+               safe_halt();
+       } else
+               local_irq_enable();
        current_thread_info()->status |= TS_POLLING;
 }
 
@@ -131,21 +128,13 @@ static void default_idle(void)
 static void poll_idle (void)
 {
        local_irq_enable();
-
-       asm volatile(
-               "2:"
-               "testl %0,%1;"
-               "rep; nop;"
-               "je 2b;"
-               : :
-               "i" (_TIF_NEED_RESCHED),
-               "m" (current_thread_info()->flags));
+       cpu_relax();
 }
 
 void cpu_idle_wait(void)
 {
        unsigned int cpu, this_cpu = get_cpu();
-       cpumask_t map;
+       cpumask_t map, tmp = current->cpus_allowed;
 
        set_cpus_allowed(current, cpumask_of_cpu(this_cpu));
        put_cpu();
@@ -168,6 +157,8 @@ void cpu_idle_wait(void)
                }
                cpus_and(map, map, cpu_online_map);
        } while (!cpus_empty(map));
+
+       set_cpus_allowed(current, tmp);
 }
 EXPORT_SYMBOL_GPL(cpu_idle_wait);
 
@@ -218,6 +209,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
@@ -238,17 +235,32 @@ void cpu_idle (void)
  * We execute MONITOR against need_resched and enter optimized wait state
  * through MWAIT. Whenever someone changes need_resched, we would be woken
  * up from MWAIT (without an IPI).
+ *
+ * New with Core Duo processors, MWAIT can take some hints based on CPU
+ * capability.
  */
-static void mwait_idle(void)
+void mwait_idle_with_hints(unsigned long eax, unsigned long ecx)
 {
-       local_irq_enable();
+       if (!need_resched()) {
+               __monitor((void *)&current_thread_info()->flags, 0, 0);
+               smp_mb();
+               if (!need_resched())
+                       __mwait(eax, ecx);
+       }
+}
 
-       while (!need_resched()) {
+/* Default MONITOR/MWAIT with no hints, used for default C1 state */
+static void mwait_idle(void)
+{
+       if (!need_resched()) {
                __monitor((void *)&current_thread_info()->flags, 0, 0);
                smp_mb();
-               if (need_resched())
-                       break;
-               __mwait(0, 0);
+               if (!need_resched())
+                       __sti_mwait(0, 0);
+               else
+                       local_irq_enable();
+       } else {
+               local_irq_enable();
        }
 }