diff options
author | Keir Fraser <keir@xen.org> | 2011-04-15 08:52:08 +0100 |
---|---|---|
committer | Keir Fraser <keir@xen.org> | 2011-04-15 08:52:08 +0100 |
commit | 8d24303023ec82d94f97154785302d52e9917f91 (patch) | |
tree | e28fc5abc76a74469c7258d6efe7f724ad951449 /xen/arch/x86/time.c | |
parent | 486fa85e92c675a03e9bc482e02d7af2d00dc81e (diff) | |
download | xen-8d24303023ec82d94f97154785302d52e9917f91.tar.gz xen-8d24303023ec82d94f97154785302d52e9917f91.tar.bz2 xen-8d24303023ec82d94f97154785302d52e9917f91.zip |
x86: don't write_tsc() non-zero values on CPUs updating only the lower 32 bits
This means suppressing the uses in time_calibration_tsc_rendezvous(),
cstate_restore_tsc(), and synchronize_tsc_slave(), and fixes a boot
hang of Linux Dom0 when loading processor.ko on such systems that
have support for C states above C1.
Signed-off-by: Jan Beulich <jbeulich@novell.com>
Signed-off-by: Keir Fraser <keir@xen.org>
Diffstat (limited to 'xen/arch/x86/time.c')
-rw-r--r-- | xen/arch/x86/time.c | 67 |
1 files changed, 66 insertions, 1 deletions
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c index 2928114f96..88331e2b90 100644 --- a/xen/arch/x86/time.c +++ b/xen/arch/x86/time.c @@ -21,6 +21,7 @@ #include <xen/smp.h> #include <xen/irq.h> #include <xen/softirq.h> +#include <xen/cpuidle.h> #include <xen/symbols.h> #include <xen/keyhandler.h> #include <xen/guest_access.h> @@ -680,6 +681,8 @@ void cstate_restore_tsc(void) if ( boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) return; + ASSERT(boot_cpu_has(X86_FEATURE_TSC_RELIABLE)); + write_tsc(stime2tsc(read_platform_stime())); } @@ -1382,6 +1385,66 @@ void init_percpu_time(void) } } +/* + * On certain older Intel CPUs writing the TSC MSR clears the upper 32 bits. + * Obviously we must not use write_tsc() on such CPUs. + * + * Additionally, AMD specifies that being able to write the TSC MSR is not an + * architectural feature (but, other than their manual says, also cannot be + * determined from CPUID bits). + */ +static void __init tsc_check_writability(void) +{ + const char *what = NULL; + uint64_t tsc; + + /* + * If all CPUs are reported as synchronised and in sync, we never write + * the TSCs (except unavoidably, when a CPU is physically hot-plugged). + * Hence testing for writability is pointless and even harmful. + */ + if ( boot_cpu_has(X86_FEATURE_TSC_RELIABLE) ) + return; + + rdtscll(tsc); + if ( wrmsr_safe(MSR_IA32_TSC, 0) == 0 ) + { + uint64_t tmp, tmp2; + rdtscll(tmp2); + write_tsc(tsc | (1ULL << 32)); + rdtscll(tmp); + if ( ABS((s64)tmp - (s64)tmp2) < (1LL << 31) ) + what = "only partially"; + } + else + { + what = "not"; + } + + /* Nothing to do if the TSC is fully writable. */ + if ( !what ) + { + /* + * Paranoia - write back original TSC value. However, APs get synced + * with BSP as they are brought up, so this doesn't much matter. + */ + write_tsc(tsc); + return; + } + + printk(XENLOG_WARNING "TSC %s writable\n", what); + + /* time_calibration_tsc_rendezvous() must not be used */ + setup_clear_cpu_cap(X86_FEATURE_CONSTANT_TSC); + + /* cstate_restore_tsc() must not be used (or do nothing) */ + if ( !boot_cpu_has(X86_FEATURE_NONSTOP_TSC) ) + cpuidle_disable_deep_cstate(); + + /* synchronize_tsc_slave() must do nothing */ + disable_tsc_sync = 1; +} + /* Late init function (after all CPUs are booted). */ int __init init_xen_time(void) { @@ -1398,6 +1461,8 @@ int __init init_xen_time(void) setup_clear_cpu_cap(X86_FEATURE_TSC_RELIABLE); } + tsc_check_writability(); + /* If we have constant-rate TSCs then scale factor can be shared. */ if ( boot_cpu_has(X86_FEATURE_CONSTANT_TSC) ) { @@ -1451,7 +1516,7 @@ static int _disable_pit_irq(void(*hpet_broadcast_setup)(void)) * XXX dom0 may rely on RTC interrupt delivery, so only enable * hpet_broadcast if FSB mode available or if force_hpet_broadcast. */ - if ( xen_cpuidle && !boot_cpu_has(X86_FEATURE_ARAT) ) + if ( cpuidle_using_deep_cstate() && !boot_cpu_has(X86_FEATURE_ARAT) ) { hpet_broadcast_setup(); if ( !hpet_broadcast_is_available() ) |