aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/time.c
diff options
context:
space:
mode:
authorKeir Fraser <keir.fraser@citrix.com>2010-02-08 10:14:48 +0000
committerKeir Fraser <keir.fraser@citrix.com>2010-02-08 10:14:48 +0000
commite0e58ddbf357108ffc0e7db8611f8623d4c68c55 (patch)
treee970c4d55c8cbbb6e4225734fac27e4aa69d5a46 /xen/arch/x86/time.c
parent2f98a8cad0104408eb0fa36b87d7d474d9e98792 (diff)
downloadxen-e0e58ddbf357108ffc0e7db8611f8623d4c68c55.tar.gz
xen-e0e58ddbf357108ffc0e7db8611f8623d4c68c55.tar.bz2
xen-e0e58ddbf357108ffc0e7db8611f8623d4c68c55.zip
Some time-handling fixes.
Fixes my domU boot hangs (when using vtsc) due to vtsc_offset less then local cpu's stime_local_stamp, leading to bogus vcpu_time_info.tsc_timestamp. Signed-off-by: Keir Fraser <keir.fraser@citrix.com>
Diffstat (limited to 'xen/arch/x86/time.c')
-rw-r--r--xen/arch/x86/time.c40
1 files changed, 28 insertions, 12 deletions
diff --git a/xen/arch/x86/time.c b/xen/arch/x86/time.c
index 29c8659d24..055c7c7b95 100644
--- a/xen/arch/x86/time.c
+++ b/xen/arch/x86/time.c
@@ -827,14 +827,14 @@ static void __update_vcpu_system_time(struct vcpu *v, int force)
u = &vcpu_info(v, time);
if ( d->arch.vtsc )
- tsc_stamp = scale_delta(t->stime_local_stamp - d->arch.vtsc_offset,
- &d->arch.ns_to_vtsc);
+ {
+ u64 delta = max_t(s64, t->stime_local_stamp - d->arch.vtsc_offset, 0);
+ tsc_stamp = scale_delta(delta, &d->arch.ns_to_vtsc);
+ }
else
+ {
tsc_stamp = t->local_tsc_stamp;
-
- /* Don't bother unless timestamps have changed or we are forced. */
- if ( !force && (u->tsc_timestamp == tsc_stamp) )
- return;
+ }
memset(&_u, 0, sizeof(_u));
@@ -853,6 +853,11 @@ static void __update_vcpu_system_time(struct vcpu *v, int force)
_u.tsc_shift = (s8)t->tsc_scale.shift;
}
+ /* Don't bother unless timestamp record has changed or we are forced. */
+ _u.version = u->version; /* make versions match for memcmp test */
+ if ( !force && !memcmp(u, &_u, sizeof(_u)) )
+ return;
+
/* 1. Update guest kernel version. */
_u.version = u->version = version_update_begin(u->version);
wmb();
@@ -1617,6 +1622,7 @@ void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs, int rdtscp)
{
s_time_t now = get_s_time();
struct domain *d = v->domain;
+ u64 delta;
spin_lock(&d->arch.vtsc_lock);
@@ -1632,7 +1638,8 @@ void pv_soft_rdtsc(struct vcpu *v, struct cpu_user_regs *regs, int rdtscp)
spin_unlock(&d->arch.vtsc_lock);
- now = scale_delta(now - d->arch.vtsc_offset, &d->arch.ns_to_vtsc);
+ delta = max_t(s64, now - d->arch.vtsc_offset, 0);
+ now = scale_delta(delta, &d->arch.ns_to_vtsc);
regs->eax = (uint32_t)now;
regs->edx = (uint32_t)(now >> 32);
@@ -1693,7 +1700,9 @@ void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
uint32_t *incarnation)
{
*incarnation = d->arch.incarnation;
- switch ( *tsc_mode = d->arch.tsc_mode )
+ *tsc_mode = d->arch.tsc_mode;
+
+ switch ( *tsc_mode )
{
case TSC_MODE_NEVER_EMULATE:
*elapsed_nsec = *gtsc_khz = 0;
@@ -1707,7 +1716,9 @@ void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
{
*elapsed_nsec = get_s_time() - d->arch.vtsc_offset;
*gtsc_khz = d->arch.tsc_khz;
- } else {
+ }
+ else
+ {
uint64_t tsc = 0;
rdtscll(tsc);
*elapsed_nsec = scale_delta(tsc,&d->arch.vtsc_to_ns);
@@ -1719,15 +1730,20 @@ void tsc_get_info(struct domain *d, uint32_t *tsc_mode,
{
*elapsed_nsec = get_s_time() - d->arch.vtsc_offset;
*gtsc_khz = cpu_khz;
- } else {
+ }
+ else
+ {
uint64_t tsc = 0;
rdtscll(tsc);
- *elapsed_nsec = scale_delta(tsc,&d->arch.vtsc_to_ns) -
- d->arch.vtsc_offset;
+ *elapsed_nsec = (scale_delta(tsc,&d->arch.vtsc_to_ns) -
+ d->arch.vtsc_offset);
*gtsc_khz = 0; /* ignored by tsc_set_info */
}
break;
}
+
+ if ( (int64_t)*elapsed_nsec < 0 )
+ *elapsed_nsec = 0;
}
/*