diff options
author | Keir Fraser <keir.fraser@citrix.com> | 2010-02-08 10:14:48 +0000 |
---|---|---|
committer | Keir Fraser <keir.fraser@citrix.com> | 2010-02-08 10:14:48 +0000 |
commit | e0e58ddbf357108ffc0e7db8611f8623d4c68c55 (patch) | |
tree | e970c4d55c8cbbb6e4225734fac27e4aa69d5a46 /xen/arch/x86/time.c | |
parent | 2f98a8cad0104408eb0fa36b87d7d474d9e98792 (diff) | |
download | xen-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.c | 40 |
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; } /* |