aboutsummaryrefslogtreecommitdiffstats
path: root/xen/arch/x86/hvm/hpet.c
diff options
context:
space:
mode:
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-01-18 18:54:28 +0000
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>2007-01-18 18:54:28 +0000
commitf545359b1c54f59be9d7c27112a68c51c45b06b5 (patch)
tree3cd69041e8eacd6d2e151151ef7e995ff08d7167 /xen/arch/x86/hvm/hpet.c
parent1a9914c007b3bd8620ddd95bed7874dd642cf36c (diff)
downloadxen-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.c24
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(