mirror of
https://github.com/xen-project/xen.git
synced 2026-10-28 10:11:27 +01:00
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>
This commit is contained in:
1 parent
486fa85e92
commit
8d24303023
6 files changed
+88
-2
No files matched your search
@@ -1098,3 +1098,7 @@ void cpuidle_disable_deep_cstate(void)
|
||||
hpet_disable_legacy_broadcast();
|
||||
}
|
||||
|
||||
bool_t cpuidle_using_deep_cstate(void)
|
||||
{
|
||||
return xen_cpuidle && max_cstate > (local_apic_timer_c2_ok ? 2 : 1);
|
||||
}
|
||||
@@ -41,6 +41,7 @@
|
||||
#include <asm/flushtlb.h>
|
||||
#include <asm/msr.h>
|
||||
#include <asm/mtrr.h>
|
||||
#include <asm/time.h>
|
||||
#include <mach_apic.h>
|
||||
#include <mach_wakecpu.h>
|
||||
#include <smpboot_hooks.h>
|
||||
@@ -124,6 +125,12 @@ static void smp_store_cpu_info(int id)
|
||||
;
|
||||
}
|
||||
|
||||
/*
|
||||
* TSC's upper 32 bits can't be written in earlier CPUs (before
|
||||
* Prescott), there is no way to resync one AP against BP.
|
||||
*/
|
||||
bool_t disable_tsc_sync;
|
||||
|
||||
static atomic_t tsc_count;
|
||||
static uint64_t tsc_value;
|
||||
static cpumask_t tsc_sync_cpu_mask;
|
||||
@@ -132,6 +139,9 @@ static void synchronize_tsc_master(unsigned int slave)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if ( disable_tsc_sync )
|
||||
return;
|
||||
|
||||
if ( boot_cpu_has(X86_FEATURE_TSC_RELIABLE) &&
|
||||
!cpu_isset(slave, tsc_sync_cpu_mask) )
|
||||
return;
|
||||
@@ -153,6 +163,9 @@ static void synchronize_tsc_slave(unsigned int slave)
|
||||
{
|
||||
unsigned int i;
|
||||
|
||||
if ( disable_tsc_sync )
|
||||
return;
|
||||
|
||||
if ( boot_cpu_has(X86_FEATURE_TSC_RELIABLE) &&
|
||||
!cpu_isset(slave, tsc_sync_cpu_mask) )
|
||||
return;
|
||||
|
||||
+66
-1
@@ -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() )
|
||||
|
||||
@@ -4,7 +4,6 @@
|
||||
#include <xen/multiboot.h>
|
||||
|
||||
extern bool_t early_boot;
|
||||
extern s8 xen_cpuidle;
|
||||
extern unsigned long xenheap_initial_phys_start;
|
||||
|
||||
void init_done(void);
|
||||
|
||||
@@ -24,6 +24,8 @@
|
||||
|
||||
typedef u64 cycles_t;
|
||||
|
||||
extern bool_t disable_tsc_sync;
|
||||
|
||||
static inline cycles_t get_cycles(void)
|
||||
{
|
||||
cycles_t c;
|
||||
|
||||
@@ -85,7 +85,10 @@ struct cpuidle_governor
|
||||
void (*reflect) (struct acpi_processor_power *dev);
|
||||
};
|
||||
|
||||
extern s8 xen_cpuidle;
|
||||
extern struct cpuidle_governor *cpuidle_current_governor;
|
||||
|
||||
bool_t cpuidle_using_deep_cstate(void);
|
||||
void cpuidle_disable_deep_cstate(void);
|
||||
|
||||
extern void cpuidle_wakeup_mwait(cpumask_t *mask);
|
||||
|
||||