diff options
author | Jan Beulich <jbeulich@suse.com> | 2012-09-25 08:36:33 +0200 |
---|---|---|
committer | Jan Beulich <jbeulich@suse.com> | 2012-09-25 08:36:33 +0200 |
commit | 797b603c7e32459c782ec2738fa6a30b4fbbcb83 (patch) | |
tree | f40d33af32a9e3ab1fe89f62b2eb937d5df4f400 | |
parent | 1b33d3acd1a7550b858379f38e01e085dc444d08 (diff) | |
download | xen-797b603c7e32459c782ec2738fa6a30b4fbbcb83.tar.gz xen-797b603c7e32459c782ec2738fa6a30b4fbbcb83.tar.bz2 xen-797b603c7e32459c782ec2738fa6a30b4fbbcb83.zip |
x86: fix MWAIT-based idle driver for CPUs without ARAT
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>
-rw-r--r-- | xen/arch/x86/acpi/cpu_idle.c | 42 | ||||
-rw-r--r-- | xen/arch/x86/cpu/mwait-idle.c | 7 | ||||
-rw-r--r-- | xen/arch/x86/hpet.c | 2 | ||||
-rw-r--r-- | xen/include/asm-x86/cpuidle.h | 1 |
4 files changed, 33 insertions, 19 deletions
diff --git a/xen/arch/x86/acpi/cpu_idle.c b/xen/arch/x86/acpi/cpu_idle.c index cb3aae7e9c..45eb603242 100644 --- a/xen/arch/x86/acpi/cpu_idle.c +++ b/xen/arch/x86/acpi/cpu_idle.c @@ -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 ) diff --git a/xen/arch/x86/cpu/mwait-idle.c b/xen/arch/x86/cpu/mwait-idle.c index 5c10fd206d..6a9ca95d33 100644 --- a/xen/arch/x86/cpu/mwait-idle.c +++ b/xen/arch/x86/cpu/mwait-idle.c @@ -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> @@ -501,6 +502,12 @@ int __init mwait_idle_init(struct notifier_block *nfb) 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); diff --git a/xen/arch/x86/hpet.c b/xen/arch/x86/hpet.c index 1b9fd574e5..45f7abae7d 100644 --- a/xen/arch/x86/hpet.c +++ b/xen/arch/x86/hpet.c @@ -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); diff --git a/xen/include/asm-x86/cpuidle.h b/xen/include/asm-x86/cpuidle.h index 73edf90efd..ac1dddf069 100644 --- a/xen/include/asm-x86/cpuidle.h +++ b/xen/include/asm-x86/cpuidle.h @@ -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); |