[HVM] Fix slow wallclock in x64 Vista. This is due to confusing a
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 18 Jan 2007 18:54:28 +0000 (18:54 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 18 Jan 2007 18:54:28 +0000 (18:54 +0000)
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>
xen/arch/x86/hvm/hpet.c

index 5d8ec9215088ff953cf4fe5ff823846f0544e845..e86df4e735102c0fa6dea95ca95d4ebc3d00214e 100644 (file)
@@ -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(