diff options
author | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-01-18 18:54:28 +0000 |
---|---|---|
committer | kfraser@localhost.localdomain <kfraser@localhost.localdomain> | 2007-01-18 18:54:28 +0000 |
commit | f545359b1c54f59be9d7c27112a68c51c45b06b5 (patch) | |
tree | 3cd69041e8eacd6d2e151151ef7e995ff08d7167 /xen/arch/x86/hvm/hpet.c | |
parent | 1a9914c007b3bd8620ddd95bed7874dd642cf36c (diff) | |
download | xen-f545359b1c54f59be9d7c27112a68c51c45b06b5.tar.gz xen-f545359b1c54f59be9d7c27112a68c51c45b06b5.tar.bz2 xen-f545359b1c54f59be9d7c27112a68c51c45b06b5.zip |
[HVM] Fix slow wallclock in x64 Vista. This is due to confusing a
timeout in the past vs. a timeout in the future when looking at a
32-bit HPET comparator.
Signed-off-by: Dexuan Cui <dexuan.cui@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
Diffstat (limited to 'xen/arch/x86/hvm/hpet.c')
-rw-r--r-- | xen/arch/x86/hvm/hpet.c | 24 |
1 files changed, 18 insertions, 6 deletions
diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c index 5d8ec92150..e86df4e735 100644 --- a/xen/arch/x86/hvm/hpet.c +++ b/xen/arch/x86/hvm/hpet.c @@ -142,9 +142,13 @@ static void hpet_stop_timer(HPETState *h, unsigned int tn) stop_timer(&h->timers[tn]); } +/* the number of HPET tick that stands for + * 1/(2^10) second, namely, 0.9765625 milliseconds */ +#define HPET_TINY_TIME_SPAN (h->tsc_freq >> 10) + static void hpet_set_timer(HPETState *h, unsigned int tn) { - uint64_t tn_cmp, cur_tick; + uint64_t tn_cmp, cur_tick, diff; ASSERT(tn < HPET_TIMER_NUM); @@ -167,11 +171,19 @@ static void hpet_set_timer(HPETState *h, unsigned int tn) cur_tick = (uint32_t)cur_tick; } - if ( (int64_t)(tn_cmp - cur_tick) > 0 ) - set_timer(&h->timers[tn], NOW() + - hpet_tick_to_ns(h, tn_cmp-cur_tick)); - else - set_timer(&h->timers[tn], NOW()); + diff = tn_cmp - cur_tick; + + /* + * Detect time values set in the past. This is hard to do for 32-bit + * comparators as the timer does not have to be set that far in the future + * for the counter difference to wrap a 32-bit signed integer. We fudge + * by looking for a 'small' time value in the past. + */ + if ( (int64_t)diff < 0 ) + diff = (timer_is_32bit(h, tn) && (-diff > HPET_TINY_TIME_SPAN)) + ? (uint32_t)diff : 0; + + set_timer(&h->timers[tn], NOW() + hpet_tick_to_ns(h, diff)); } static inline uint64_t hpet_fixup_reg( |