Merge git://git.kernel.org/pub/scm/linux/kernel/git/davem/sparc-2.6
[linux-2.6-block.git] / drivers / acpi / processor_idle.c
index 2fe34cc73c1327a191a48aee32b70ee14c922c9e..32003fdc91e8a4b0205f3fbf2bedfbfc91260399 100644 (file)
@@ -38,7 +38,7 @@
 #include <linux/dmi.h>
 #include <linux/moduleparam.h>
 #include <linux/sched.h>       /* need_resched() */
-#include <linux/latency.h>
+#include <linux/pm_qos_params.h>
 #include <linux/clockchips.h>
 #include <linux/cpuidle.h>
 
@@ -76,7 +76,11 @@ static void (*pm_idle_save) (void) __read_mostly;
 #define PM_TIMER_TICKS_TO_US(p)                (((p) * 1000)/(PM_TIMER_FREQUENCY/1000))
 
 static unsigned int max_cstate __read_mostly = ACPI_PROCESSOR_MAX_POWER;
+#ifdef CONFIG_CPU_IDLE
 module_param(max_cstate, uint, 0000);
+#else
+module_param(max_cstate, uint, 0644);
+#endif
 static unsigned int nocst __read_mostly;
 module_param(nocst, uint, 0000);
 
@@ -94,6 +98,9 @@ module_param(bm_history, uint, 0644);
 
 static int acpi_processor_set_power_policy(struct acpi_processor *pr);
 
+#else  /* CONFIG_CPU_IDLE */
+static unsigned int latency_factor __read_mostly = 2;
+module_param(latency_factor, uint, 0644);
 #endif
 
 /*
@@ -197,6 +204,10 @@ static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
                return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
 }
 
+/*
+ * Callers should disable interrupts before the call and enable
+ * interrupts after return.
+ */
 static void acpi_safe_halt(void)
 {
        current_thread_info()->status &= ~TS_POLLING;
@@ -257,7 +268,7 @@ static atomic_t c3_cpu_count;
 /* Common C-state entry for C2, C3, .. */
 static void acpi_cstate_enter(struct acpi_processor_cx *cstate)
 {
-       if (cstate->space_id == ACPI_CSTATE_FFH) {
+       if (cstate->entry_method == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cstate);
        } else {
@@ -353,6 +364,26 @@ int acpi_processor_resume(struct acpi_device * device)
        return 0;
 }
 
+#if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
+static int tsc_halts_in_c(int state)
+{
+       switch (boot_cpu_data.x86_vendor) {
+       case X86_VENDOR_AMD:
+               /*
+                * AMD Fam10h TSC will tick in all
+                * C/P/S0/S1 states when this bit is set.
+                */
+               if (boot_cpu_has(X86_FEATURE_CONSTANT_TSC))
+                       return 0;
+               /*FALL THROUGH*/
+       case X86_VENDOR_INTEL:
+               /* Several cases known where TSC halts in C2 too */
+       default:
+               return state > ACPI_STATE_C1;
+       }
+}
+#endif
+
 #ifndef CONFIG_CPU_IDLE
 static void acpi_processor_idle(void)
 {
@@ -389,6 +420,8 @@ static void acpi_processor_idle(void)
                        pm_idle_save();
                else
                        acpi_safe_halt();
+
+               local_irq_enable();
                return;
        }
 
@@ -497,6 +530,7 @@ static void acpi_processor_idle(void)
                 *       skew otherwise.
                 */
                sleep_ticks = 0xFFFFFFFF;
+               local_irq_enable();
                break;
 
        case ACPI_STATE_C2:
@@ -512,7 +546,8 @@ static void acpi_processor_idle(void)
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C2, so notify users */
-               mark_tsc_unstable("possible TSC halt in C2");
+               if (tsc_halts_in_c(ACPI_STATE_C2))
+                       mark_tsc_unstable("possible TSC halt in C2");
 #endif
                /* Compute time (ticks) that we were actually asleep */
                sleep_ticks = ticks_elapsed(t1, t2);
@@ -530,6 +565,7 @@ static void acpi_processor_idle(void)
                break;
 
        case ACPI_STATE_C3:
+               acpi_unlazy_tlb(smp_processor_id());
                /*
                 * Must be done before busmaster disable as we might
                 * need to access HPET !
@@ -575,7 +611,8 @@ static void acpi_processor_idle(void)
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
                /* TSC halts in C3, so notify users */
-               mark_tsc_unstable("TSC halts in C3");
+               if (tsc_halts_in_c(ACPI_STATE_C3))
+                       mark_tsc_unstable("TSC halts in C3");
 #endif
                /* Compute time (ticks) that we were actually asleep */
                sleep_ticks = ticks_elapsed(t1, t2);
@@ -621,7 +658,8 @@ static void acpi_processor_idle(void)
        if (cx->promotion.state &&
            ((cx->promotion.state - pr->power.states) <= max_cstate)) {
                if (sleep_ticks > cx->promotion.threshold.ticks &&
-                 cx->promotion.state->latency <= system_latency_constraint()) {
+                 cx->promotion.state->latency <=
+                               pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
                        cx->promotion.count++;
                        cx->demotion.count = 0;
                        if (cx->promotion.count >=
@@ -665,7 +703,8 @@ static void acpi_processor_idle(void)
         * or if the latency of the current state is unacceptable
         */
        if ((pr->power.state - pr->power.states) > max_cstate ||
-               pr->power.state->latency > system_latency_constraint()) {
+               pr->power.state->latency >
+                               pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY)) {
                if (cx->demotion.state)
                        next_state = cx->demotion.state;
        }
@@ -893,20 +932,20 @@ static int acpi_processor_get_power_info_cst(struct acpi_processor *pr)
                cx.address = reg->address;
                cx.index = current_count + 1;
 
-               cx.space_id = ACPI_CSTATE_SYSTEMIO;
+               cx.entry_method = ACPI_CSTATE_SYSTEMIO;
                if (reg->space_id == ACPI_ADR_SPACE_FIXED_HARDWARE) {
                        if (acpi_processor_ffh_cstate_probe
                                        (pr->id, &cx, reg) == 0) {
-                               cx.space_id = ACPI_CSTATE_FFH;
-                       } else if (cx.type != ACPI_STATE_C1) {
+                               cx.entry_method = ACPI_CSTATE_FFH;
+                       } else if (cx.type == ACPI_STATE_C1) {
                                /*
                                 * C1 is a special case where FIXED_HARDWARE
                                 * can be handled in non-MWAIT way as well.
                                 * In that case, save this _CST entry info.
-                                * That is, we retain space_id of SYSTEM_IO for
-                                * halt based C1.
                                 * Otherwise, ignore this info and continue.
                                 */
+                               cx.entry_method = ACPI_CSTATE_HALT;
+                       } else {
                                continue;
                        }
                }
@@ -1173,7 +1212,7 @@ static int acpi_processor_power_seq_show(struct seq_file *seq, void *offset)
                   "maximum allowed latency: %d usec\n",
                   pr->power.state ? pr->power.state - pr->power.states : 0,
                   max_cstate, (unsigned)pr->power.bm_activity,
-                  system_latency_constraint());
+                  pm_qos_requirement(PM_QOS_CPU_DMA_LATENCY));
 
        seq_puts(seq, "states:\n");
 
@@ -1340,12 +1379,16 @@ static inline void acpi_idle_update_bm_rld(struct acpi_processor *pr,
 /**
  * acpi_idle_do_entry - a helper function that does C2 and C3 type entry
  * @cx: cstate data
+ *
+ * Caller disables interrupt before call and enables interrupt after return.
  */
 static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 {
-       if (cx->space_id == ACPI_CSTATE_FFH) {
+       if (cx->entry_method == ACPI_CSTATE_FFH) {
                /* Call into architectural FFH based C-state */
                acpi_processor_ffh_cstate_enter(cx);
+       } else if (cx->entry_method == ACPI_CSTATE_HALT) {
+               acpi_safe_halt();
        } else {
                int unused;
                /* IO port based C-state */
@@ -1367,21 +1410,27 @@ static inline void acpi_idle_do_entry(struct acpi_processor_cx *cx)
 static int acpi_idle_enter_c1(struct cpuidle_device *dev,
                              struct cpuidle_state *state)
 {
+       u32 t1, t2;
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
+
        pr = processors[smp_processor_id()];
 
        if (unlikely(!pr))
                return 0;
 
+       local_irq_disable();
        if (pr->flags.bm_check)
                acpi_idle_update_bm_rld(pr, cx);
 
-       acpi_safe_halt();
+       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       acpi_idle_do_entry(cx);
+       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
 
+       local_irq_enable();
        cx->usage++;
 
-       return 0;
+       return ticks_elapsed_in_us(t1, t2);
 }
 
 /**
@@ -1419,6 +1468,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
                return 0;
        }
 
+       acpi_unlazy_tlb(smp_processor_id());
        /*
         * Must be done before busmaster disable as we might need to
         * access HPET !
@@ -1439,7 +1489,8 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
        /* TSC could halt in idle, so notify users */
-       mark_tsc_unstable("TSC halts in idle");;
+       if (tsc_halts_in_c(cx->type))
+               mark_tsc_unstable("TSC halts in idle");;
 #endif
        sleep_ticks = ticks_elapsed(t1, t2);
 
@@ -1486,7 +1537,9 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                if (dev->safe_state) {
                        return dev->safe_state->enter(dev, dev->safe_state);
                } else {
+                       local_irq_disable();
                        acpi_safe_halt();
+                       local_irq_enable();
                        return 0;
                }
        }
@@ -1550,7 +1603,8 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86_TSC)
        /* TSC could halt in idle, so notify users */
-       mark_tsc_unstable("TSC halts in idle");
+       if (tsc_halts_in_c(ACPI_STATE_C3))
+               mark_tsc_unstable("TSC halts in idle");
 #endif
        sleep_ticks = ticks_elapsed(t1, t2);
        /* Tell the scheduler how much we idled: */
@@ -1577,7 +1631,7 @@ struct cpuidle_driver acpi_idle_driver = {
  */
 static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 {
-       int i, count = 0;
+       int i, count = CPUIDLE_DRIVER_STATE_START;
        struct acpi_processor_cx *cx;
        struct cpuidle_state *state;
        struct cpuidle_device *dev = &pr->power.dev;
@@ -1606,13 +1660,14 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
 
                snprintf(state->name, CPUIDLE_NAME_LEN, "C%d", i);
                state->exit_latency = cx->latency;
-               state->target_residency = cx->latency * 6;
+               state->target_residency = cx->latency * latency_factor;
                state->power_usage = cx->power;
 
                state->flags = 0;
                switch (cx->type) {
                        case ACPI_STATE_C1:
                        state->flags |= CPUIDLE_FLAG_SHALLOW;
+                       state->flags |= CPUIDLE_FLAG_TIME_VALID;
                        state->enter = acpi_idle_enter_c1;
                        dev->safe_state = state;
                        break;
@@ -1635,6 +1690,8 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
                }
 
                count++;
+               if (count == CPUIDLE_STATE_MAX)
+                       break;
        }
 
        dev->state_count = count;
@@ -1688,8 +1745,9 @@ int __cpuinit acpi_processor_power_init(struct acpi_processor *pr,
                               "ACPI: processor limited to max C-state %d\n",
                               max_cstate);
                first_run++;
-#if !defined (CONFIG_CPU_IDLE) && defined (CONFIG_SMP)
-               register_latency_notifier(&acpi_processor_latency_notifier);
+#if !defined(CONFIG_CPU_IDLE) && defined(CONFIG_SMP)
+               pm_qos_add_notifier(PM_QOS_CPU_DMA_LATENCY,
+                               &acpi_processor_latency_notifier);
 #endif
        }
 
@@ -1776,7 +1834,8 @@ int acpi_processor_power_exit(struct acpi_processor *pr,
                 */
                cpu_idle_wait();
 #ifdef CONFIG_SMP
-               unregister_latency_notifier(&acpi_processor_latency_notifier);
+               pm_qos_remove_notifier(PM_QOS_CPU_DMA_LATENCY,
+                               &acpi_processor_latency_notifier);
 #endif
        }
 #endif