x86: fix MWAIT-based idle driver for CPUs without ARAT
authorJan Beulich <jbeulich@suse.com>
Tue, 25 Sep 2012 06:36:33 +0000 (08:36 +0200)
committerJan Beulich <jbeulich@suse.com>
Tue, 25 Sep 2012 06:36:33 +0000 (08:36 +0200)
lapic_timer_{on,off} need to get initialized in this case. This in turn
requires getting HPET broadcast setup to be carried out earlier (and
hence preventing double initialization there).

Signed-off-by: Jan Beulich <jbeulich@suse.com>
xen/arch/x86/acpi/cpu_idle.c
xen/arch/x86/cpu/mwait-idle.c
xen/arch/x86/hpet.c
xen/include/asm-x86/cpuidle.h

index cb3aae7e9cf1fdc2b81e5176728225f59e3277e2..45eb6032425b83fab31f0165cc7022a15abc35b4 100644 (file)
@@ -74,6 +74,29 @@ static void lapic_timer_nop(void) { }
 void (*__read_mostly lapic_timer_off)(void);
 void (*__read_mostly lapic_timer_on)(void);
 
+bool_t lapic_timer_init(void)
+{
+    if ( boot_cpu_has(X86_FEATURE_ARAT) )
+    {
+        lapic_timer_off = lapic_timer_nop;
+        lapic_timer_on = lapic_timer_nop;
+    }
+    else if ( hpet_broadcast_is_available() )
+    {
+        lapic_timer_off = hpet_broadcast_enter;
+        lapic_timer_on = hpet_broadcast_exit;
+    }
+    else if ( pit_broadcast_is_available() )
+    {
+        lapic_timer_off = pit_broadcast_enter;
+        lapic_timer_on = pit_broadcast_exit;
+    }
+    else
+        return 0;
+
+    return 1;
+}
+
 static uint64_t (*__read_mostly tick_to_ns)(uint64_t) = acpi_pm_tick_to_ns;
 
 void (*__read_mostly pm_idle_save)(void);
@@ -789,25 +812,8 @@ static int check_cx(struct acpi_processor_power *power, xen_processor_cx_t *cx)
         if ( local_apic_timer_c2_ok )
             break;
     case ACPI_STATE_C3:
-        if ( boot_cpu_has(X86_FEATURE_ARAT) )
-        {
-            lapic_timer_off = lapic_timer_nop;
-            lapic_timer_on = lapic_timer_nop;
-        }
-        else if ( hpet_broadcast_is_available() )
-        {
-            lapic_timer_off = hpet_broadcast_enter;
-            lapic_timer_on = hpet_broadcast_exit;
-        }
-        else if ( pit_broadcast_is_available() )
-        {
-            lapic_timer_off = pit_broadcast_enter;
-            lapic_timer_on = pit_broadcast_exit;
-        }
-        else
-        {
+        if ( !lapic_timer_init() )
             return -EINVAL;
-        }
 
         /* All the logic here assumes flags.bm_check is same across all CPUs */
         if ( bm_check_flag == -1 )
index 5c10fd206d8b0465d841f1569073a18a77e3d821..6a9ca95d33b36c52d54ec4fce54ffa91ffe6d070 100644 (file)
@@ -56,6 +56,7 @@
 #include <xen/softirq.h>
 #include <xen/trace.h>
 #include <asm/cpuidle.h>
+#include <asm/hpet.h>
 #include <asm/mwait.h>
 #include <asm/msr.h>
 #include <acpi/cpufreq/cpufreq.h>
@@ -500,6 +501,12 @@ int __init mwait_idle_init(struct notifier_block *nfb)
                return -ENODEV;
 
        err = mwait_idle_probe();
+       if (!err) {
+               if (!boot_cpu_has(X86_FEATURE_ARAT))
+                       hpet_broadcast_init();
+               if (!lapic_timer_init())
+                       err = -EINVAL;
+       }
        if (!err) {
                nfb->notifier_call = mwait_idle_cpu_init;
                mwait_idle_cpu_init(nfb, CPU_UP_PREPARE, NULL);
index 1b9fd574e5b007b4aaf3d8053fca3b41a109c992..45f7abae7d94364e9adfe38f001c3cbb9fb4691d 100644 (file)
@@ -495,7 +495,7 @@ void __init hpet_broadcast_init(void)
     u32 hpet_id, cfg;
     unsigned int i, n;
 
-    if ( hpet_rate == 0 )
+    if ( hpet_rate == 0 || hpet_broadcast_is_available() )
         return;
 
     cfg = hpet_read32(HPET_CFG);
index 73edf90efd0f665344ed01b894ade9b451a69530..ac1dddf0696b484d6de55be893e4fda427aa17c8 100644 (file)
@@ -10,6 +10,7 @@ extern struct acpi_processor_power *processor_powers[];
 
 extern void (*pm_idle_save)(void);
 
+bool_t lapic_timer_init(void);
 extern void (*lapic_timer_off)(void);
 extern void (*lapic_timer_on)(void);