ACPI: prevent processor.max_cstate=0 boot crash
[pandora-kernel.git] / drivers / acpi / processor_idle.c
index 397f2a7..436127e 100644 (file)
@@ -64,7 +64,6 @@
 #define _COMPONENT              ACPI_PROCESSOR_COMPONENT
 ACPI_MODULE_NAME("processor_idle");
 #define ACPI_PROCESSOR_FILE_POWER      "power"
-#define US_TO_PM_TIMER_TICKS(t)                ((t * (PM_TIMER_FREQUENCY/1000)) / 1000)
 #define PM_TIMER_TICK_NS               (1000000000ULL/PM_TIMER_FREQUENCY)
 #define C2_OVERHEAD                    1       /* 1us */
 #define C3_OVERHEAD                    1       /* 1us */
@@ -78,6 +77,10 @@ module_param(nocst, uint, 0000);
 static unsigned int latency_factor __read_mostly = 2;
 module_param(latency_factor, uint, 0644);
 
+static s64 us_to_pm_timer_ticks(s64 t)
+{
+       return div64_u64(t * PM_TIMER_FREQUENCY, 1000000);
+}
 /*
  * IBM ThinkPad R40e crashes mysteriously when going into C2 or C3.
  * For now disable this. Probably a bug somewhere else.
@@ -108,25 +111,6 @@ static struct dmi_system_id __cpuinitdata processor_power_dmi_table[] = {
        {},
 };
 
-static inline u32 ticks_elapsed(u32 t1, u32 t2)
-{
-       if (t2 >= t1)
-               return (t2 - t1);
-       else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
-               return (((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
-       else
-               return ((0xFFFFFFFF - t1) + t2);
-}
-
-static inline u32 ticks_elapsed_in_us(u32 t1, u32 t2)
-{
-       if (t2 >= t1)
-               return PM_TIMER_TICKS_TO_US(t2 - t1);
-       else if (!(acpi_gbl_FADT.flags & ACPI_FADT_32BIT_TIMER))
-               return PM_TIMER_TICKS_TO_US(((0x00FFFFFF - t1) + t2) & 0x00FFFFFF);
-       else
-               return PM_TIMER_TICKS_TO_US((0xFFFFFFFF - t1) + t2);
-}
 
 /*
  * Callers should disable interrupts before the call and enable
@@ -161,6 +145,9 @@ static void acpi_timer_check_state(int state, struct acpi_processor *pr,
        struct acpi_processor_power *pwr = &pr->power;
        u8 type = local_apic_timer_c2_ok ? ACPI_STATE_C3 : ACPI_STATE_C2;
 
+       if (cpu_has(&cpu_data(pr->id), X86_FEATURE_ARAT))
+               return;
+
        /*
         * Check, if one of the previous states already marked the lapic
         * unstable
@@ -802,7 +789,8 @@ 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;
+       ktime_t  kt1, kt2;
+       s64 idle_time;
        struct acpi_processor *pr;
        struct acpi_processor_cx *cx = cpuidle_get_statedata(state);
 
@@ -820,14 +808,15 @@ static int acpi_idle_enter_c1(struct cpuidle_device *dev,
                return 0;
        }
 
-       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt1 = ktime_get_real();
        acpi_idle_do_entry(cx);
-       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt2 = ktime_get_real();
+       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
 
        local_irq_enable();
        cx->usage++;
 
-       return ticks_elapsed_in_us(t1, t2);
+       return idle_time;
 }
 
 /**
@@ -840,8 +829,9 @@ 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;
+       ktime_t  kt1, kt2;
+       s64 idle_time;
+       s64 sleep_ticks = 0;
 
        pr = __get_cpu_var(processors);
 
@@ -874,18 +864,19 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
        if (cx->type == ACPI_STATE_C3)
                ACPI_FLUSH_CPU_CACHE();
 
-       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt1 = ktime_get_real();
        /* Tell the scheduler that we are going deep-idle: */
        sched_clock_idle_sleep_event();
        acpi_idle_do_entry(cx);
-       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt2 = ktime_get_real();
+       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
 
 #if defined (CONFIG_GENERIC_TIME) && defined (CONFIG_X86)
        /* TSC could halt in idle, so notify users */
        if (tsc_halts_in_c(cx->type))
                mark_tsc_unstable("TSC halts in idle");;
 #endif
-       sleep_ticks = ticks_elapsed(t1, t2);
+       sleep_ticks = us_to_pm_timer_ticks(idle_time);
 
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
@@ -897,7 +888,7 @@ static int acpi_idle_enter_simple(struct cpuidle_device *dev,
 
        acpi_state_timer_broadcast(pr, cx, 0);
        cx->time += sleep_ticks;
-       return ticks_elapsed_in_us(t1, t2);
+       return idle_time;
 }
 
 static int c3_cpu_count;
@@ -915,8 +906,10 @@ 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;
+       ktime_t  kt1, kt2;
+       s64 idle_time;
+       s64 sleep_ticks = 0;
+
 
        pr = __get_cpu_var(processors);
 
@@ -983,9 +976,10 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
                ACPI_FLUSH_CPU_CACHE();
        }
 
-       t1 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt1 = ktime_get_real();
        acpi_idle_do_entry(cx);
-       t2 = inl(acpi_gbl_FADT.xpm_timer_block.address);
+       kt2 = ktime_get_real();
+       idle_time =  ktime_to_us(ktime_sub(kt2, kt1));
 
        /* Re-enable bus master arbitration */
        if (pr->flags.bm_check && pr->flags.bm_control) {
@@ -1000,7 +994,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
        if (tsc_halts_in_c(ACPI_STATE_C3))
                mark_tsc_unstable("TSC halts in idle");
 #endif
-       sleep_ticks = ticks_elapsed(t1, t2);
+       sleep_ticks = us_to_pm_timer_ticks(idle_time);
        /* Tell the scheduler how much we idled: */
        sched_clock_idle_wakeup_event(sleep_ticks*PM_TIMER_TICK_NS);
 
@@ -1011,7 +1005,7 @@ static int acpi_idle_enter_bm(struct cpuidle_device *dev,
 
        acpi_state_timer_broadcast(pr, cx, 0);
        cx->time += sleep_ticks;
-       return ticks_elapsed_in_us(t1, t2);
+       return idle_time;
 }
 
 struct cpuidle_driver acpi_idle_driver = {
@@ -1043,6 +1037,9 @@ static int acpi_processor_setup_cpuidle(struct acpi_processor *pr)
                dev->states[i].desc[0] = '\0';
        }
 
+       if (max_cstate == 0)
+               max_cstate = 1;
+
        for (i = 1; i < ACPI_PROCESSOR_MAX_POWER && i <= max_cstate; i++) {
                cx = &pr->power.states[i];
                state = &dev->states[count];