Merge git://git.kernel.org/pub/scm/linux/kernel/git/x86/linux-2.6-x86
[linux-2.6.git] / drivers / acpi / processor_idle.c
index b52109bd06d2bd0bbb0b2084912a9aa2a75959db..b1fbee3f7fe1aff55771ccef5cdee7dc703ac901 100644 (file)
@@ -197,6 +197,19 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
                return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
 }
 
+static void acpi_safe_halt(void)
+{
+       current_thread_info()->status &= ~TS_POLLING;
+       /*
+        * 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;
+}
+
 #ifndef CONFIG_CPU_IDLE
 
 static void
@@ -239,19 +252,6 @@ acpi_processor_power_activate(struct acpi_processor *pr,
        return;
 }
 
-static void acpi_safe_halt(void)
-{
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * 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;
-}
-
 static atomic_t c3_cpu_count;
 
 /* Common C-state entry for C2, C3, .. */
@@ -1373,15 +1373,7 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
        if (pr->flags.bm_check)
                acpi_idle_update_bm_rld(pr, cx);
 
-       current_thread_info()->status &= ~TS_POLLING;
-       /*
-        * 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;
+       acpi_safe_halt();
 
        cx->usage++;
 
@@ -1399,6 +1391,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        u32 t1, t2;
+       int sleep_ticks = 0;
+
        pr = processors[smp_processor_id()];
 
        if (unlikely(!pr))
@@ -1428,6 +1422,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                ACPI_FLUSH_CPU_CACHE();
 
        t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       /* Tell the scheduler that we are going deep-idle: */
+       sched_clock_idle_sleep_event();
        acpi_state_timer_broadcast(pr, cx, 1);
        acpi_idle_do_entry(cx);
        t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
@@ -1436,6 +1432,10 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        /* TSC could halt in idle, so notify users */
        mark_tsc_unstable("TSC halts in idle");;
 #endif
+       sleep_ticks = ticks_elapsed(t1, t2);
+
+       /* Tell the scheduler how much we idled: */
+       sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
 
        local_irq_enable();
        current_thread_info()->status |= TS_POLLING;
@@ -1443,7 +1443,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        cx->usage++;
 
        acpi_state_timer_broadcast(pr, cx, 0);
-       cx->time += ticks_elapsed(t1, t2);
+       cx->time += sleep_ticks;
        return ticks_elapsed_in_us(t1, t2);
 }
 
@@ -1463,6 +1463,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
        u32 t1, t2;
+       int sleep_ticks = 0;
+
        pr = processors[smp_processor_id()];
 
        if (unlikely(!pr))
@@ -1471,6 +1473,15 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        if (acpi_idle_suspend)
                return(acpi_idle_enter_c1(dev, state));
 
+       if (acpi_idle_bm_check()) {
+               if (dev->safe_state) {
+                       return dev->safe_state->enter(dev, dev->safe_state);
+               } else {
+                       acpi_safe_halt();
+                       return 0;
+               }
+       }
+
        local_irq_disable();
        current_thread_info()->status &= ~TS_POLLING;
        /*
@@ -1485,38 +1496,45 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                return 0;
        }
 
+       /* Tell the scheduler that we are going deep-idle: */
+       sched_clock_idle_sleep_event();
        /*
         * Must be done before busmaster disable as we might need to
         * access HPET !
         */
        acpi_state_timer_broadcast(pr, cx, 1);
 
-       if (acpi_idle_bm_check()) {
-               cx = pr->power.bm_state;
-
-               acpi_idle_update_bm_rld(pr, cx);
-
-               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-               acpi_idle_do_entry(cx);
-               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-       } else {
-               acpi_idle_update_bm_rld(pr, cx);
+       acpi_idle_update_bm_rld(pr, cx);
 
+       /*
+        * disable bus master
+        * bm_check implies we need ARB_DIS
+        * !bm_check implies we need cache flush
+        * bm_control implies whether we can do ARB_DIS
+        *
+        * That leaves a case where bm_check is set and bm_control is
+        * not set. In that case we cannot do much, we enter C3
+        * without doing anything.
+        */
+       if (pr->flags.bm_check && pr->flags.bm_control) {
                spin_lock(&c3_lock);
                c3_cpu_count++;
                /* Disable bus master arbitration when all CPUs are in C3 */
                if (c3_cpu_count == num_online_cpus())
                        acpi_set_register(ACPI_BITREG_ARB_DISABLE, 1);
                spin_unlock(&c3_lock);
+       } else if (!pr->flags.bm_check) {
+               ACPI_FLUSH_CPU_CACHE();
+       }
 
-               t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
-               acpi_idle_do_entry(cx);
-               t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       acpi_idle_do_entry(cx);
+       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
+       /* Re-enable bus master arbitration */
+       if (pr->flags.bm_check && pr->flags.bm_control) {
                spin_lock(&c3_lock);
-               /* Re-enable bus master arbitration */
-               if (c3_cpu_count == num_online_cpus())
-                       acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
+               acpi_set_register(ACPI_BITREG_ARB_DISABLE, 0);
                c3_cpu_count--;
                spin_unlock(&c3_lock);
        }
@@ -1525,6 +1543,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        /* TSC could halt in idle, so notify users */
        mark_tsc_unstable("TSC halts in idle");
 #endif
+       sleep_ticks = ticks_elapsed(t1, t2);
+       /* Tell the scheduler how much we idled: */
+       sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
 
        local_irq_enable();
        current_thread_info()->status |= TS_POLLING;
@@ -1532,7 +1553,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        cx->usage++;
 
        acpi_state_timer_broadcast(pr, cx, 0);
-       cx->time += ticks_elapsed(t1, t2);
+       cx->time += sleep_ticks;
        return ticks_elapsed_in_us(t1, t2);
 }
 
@@ -1584,12 +1605,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
                        case ACPI_STATE_C1:
                        state->flags |= CPUIDLE_FLAG_SHALLOW;
                        state->enter = acpi_idle_enter_c1;
+                       dev->safe_state = state;
                        break;
 
                        case ACPI_STATE_C2:
                        state->flags |= CPUIDLE_FLAG_BALANCED;
                        state->flags |= CPUIDLE_FLAG_TIME_VALID;
                        state->enter = acpi_idle_enter_simple;
+                       dev->safe_state = state;
                        break;
 
                        case ACPI_STATE_C3:
@@ -1610,14 +1633,6 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
        if (!count)
                return -EINVAL;
 
-       /* find the deepest state that can handle active BM */
-       if (pr->flags.bm_check) {
-               for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++)
-                       if (pr->power.states[i].type == ACPI_STATE_C3)
-                               break;
-               pr->power.bm_state = &pr->power.states[i-1];
-       }
-
        return 0;
 }