Improve HPET comparator reprog to prevent intr-near-missing case
authorKeir Fraser <keir.fraser@citrix.com>
Tue, 3 Jun 2008 08:41:19 +0000 (09:41 +0100)
committerKeir Fraser <keir.fraser@citrix.com>
Tue, 3 Jun 2008 08:41:19 +0000 (09:41 +0100)
HPET intr-near-missing means if the current counter value is too close
to the comparator value to be reprogrammed the expected HPET intr may
be missing. Linux kernel uses a mininal 48-hpet-ticks(~3.5us) distance
to workaround this, but personal observation showed there is still
failure case while delta=3D0xba (~13.5us). So choosing 20us as the
MIN_DELTA_NS should be helpful to prevent near-missing from happening.

local_irq_save/restore were used to avoid disturbance. (+ 2) was used
as a final guard to avoid wrong judgement due to the real happened
near-missing case.

Signed-off-by: Wei Gang <gang.wei@intel.com>
Signed-off-by: Tian Kevin <kevin.tian@intel.com>
xen/arch/x86/hpet.c

index 16d9d3efd2a3ae15567ce493a9e87152b28e008b..5c4b53ea75bf34f728839ee20953c4f0801ead29 100644 (file)
@@ -17,7 +17,7 @@
 #define STIME_MAX ((s_time_t)((uint64_t)~0ull>>1))
 
 #define MAX_DELTA_NS MILLISECS(10*1000)
-#define MIN_DELTA_NS MICROSECS(1)
+#define MIN_DELTA_NS MICROSECS(20)
 
 struct hpet_event_channel
 {
@@ -67,13 +67,18 @@ static inline unsigned long ns2ticks(unsigned long nsec, int shift,
 
 static int hpet_legacy_next_event(unsigned long delta)
 {
-    unsigned long cnt;
+    uint32_t cnt, cmp;
+    unsigned long flags;
 
+    local_irq_save(flags);
     cnt = hpet_read32(HPET_COUNTER);
-    cnt += delta;
-    hpet_write32(cnt, HPET_T0_CMP);
+    cmp = cnt + delta;
+    hpet_write32(cmp, HPET_T0_CMP);
+    cmp = hpet_read32(HPET_COUNTER);
+    local_irq_restore(flags);
 
-    return ((long)(hpet_read32(HPET_COUNTER) - cnt) > 0) ? -ETIME : 0;
+    /* Are we within two ticks of the deadline passing? Then we may miss. */
+    return ((cmp + 2 - cnt) > delta) ? -ETIME : 0;
 }
 
 static int reprogram_hpet_evt_channel(