[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] [PATCH v2 10/10] hvm/hpet: handle 1st period special



The software-developers-hpet-spec-1-0a.pdf says that the 1st
interrupt is based on the setting of comparator.  After that it will
be on each period.  Add code that checks for this special case.

Add a callback routine when this special case is active that
will disable the special case on the 1st interrupt.

Signed-off-by: Don Slutz <dslutz@xxxxxxxxxxx>
---
 xen/arch/x86/hvm/hpet.c       | 56 +++++++++++++++++++++++++++++++++++++------
 xen/include/asm-x86/hvm/vpt.h |  2 ++
 2 files changed, 51 insertions(+), 7 deletions(-)

diff --git a/xen/arch/x86/hvm/hpet.c b/xen/arch/x86/hvm/hpet.c
index 3226a61..f8ed792 100644
--- a/xen/arch/x86/hvm/hpet.c
+++ b/xen/arch/x86/hvm/hpet.c
@@ -94,10 +94,18 @@ static uint64_t hpet_get_comparator(HPETState *h, unsigned 
int tn,
     {
         /* update comparator by number of periods elapsed since last update */
         uint64_t period = h->hpet.period[tn];
+        uint64_t mc = hpet_read_maincounter(h, guest_time);
+
+        if ( h->hpet.first_enabled[tn] )
+        {
+            if ( mc >= h->hpet.first_mc64[tn] && mc < comparator )
+                period = 0; /* act like oneshot */
+            else
+                h->hpet.first_enabled[tn] = 0;
+        }
         if (period)
         {
-            elapsed = hpet_read_maincounter(h, guest_time) +
-                period - comparator;
+            elapsed = mc + period - comparator;
             comparator += (elapsed / period) * period;
             h->hpet.comparator64[tn] = comparator;
         }
@@ -203,6 +211,13 @@ static void hpet_stop_timer(HPETState *h, unsigned int tn)
  * 1/(2^10) second, namely, 0.9765625 milliseconds */
 #define  HPET_TINY_TIME_SPAN  ((h->stime_freq >> 10) / STIME_PER_HPET_TICK)
 
+static void hpet_time_fired(struct vcpu *v, void *priv)
+{
+    uint8_t *first_enabled_p = (uint8_t *)priv;
+
+    *first_enabled_p = 0;
+}
+
 static void hpet_set_timer(HPETState *h, unsigned int tn, int mc_starting)
 {
     uint64_t tn_cmp, cur_tick, diff;
@@ -223,8 +238,16 @@ static void hpet_set_timer(HPETState *h, unsigned int tn, 
int mc_starting)
     if ( !timer_enabled(h, tn) )
         return;
 
+    oneshot = !timer_is_periodic(h, tn);
     if ( mc_starting )
+    {
         guest_time = h->hpet.mc64 - h->mc_offset;
+        if ( !oneshot )
+        {
+            h->hpet.first_mc64[tn] = h->hpet.mc64;
+            h->hpet.first_enabled[tn] = 1;
+        }
+    }
     else
         guest_time = guest_time_hpet(h);
 
@@ -262,11 +285,27 @@ static void hpet_set_timer(HPETState *h, unsigned int tn, 
int mc_starting)
      * have elapsed between the time the comparator was written and the timer
      * being enabled (now).
      */
-    oneshot = !timer_is_periodic(h, tn);
-    create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
-                         hpet_tick_to_ns(h, diff),
-                         oneshot ? 0 : hpet_tick_to_ns(h, h->hpet.period[tn]),
-                         irq, NULL, NULL);
+    if ( oneshot )
+        create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
+                             hpet_tick_to_ns(h, diff),
+                             0, irq, NULL, NULL);
+    else
+    {
+        if ( diff <= h->hpet.period[tn] )
+        {
+            h->hpet.first_enabled[tn] = 0;
+            create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
+                                 hpet_tick_to_ns(h, diff),
+                                 hpet_tick_to_ns(h, h->hpet.period[tn]),
+                                 irq, NULL, NULL);
+        }
+        else
+            create_periodic_time(vhpet_vcpu(h), &h->pt[tn],
+                                 hpet_tick_to_ns(h, diff),
+                                 hpet_tick_to_ns(h, h->hpet.period[tn]),
+                                 irq, hpet_time_fired,
+                                 &h->hpet.first_enabled[tn]);
+    }
 }
 
 static inline uint64_t hpet_fixup_reg(
@@ -591,6 +630,9 @@ static int hpet_load(struct domain *d, hvm_domain_context_t 
*h)
         if ( timer_is_32bit(hp, i) )
             cmp = (uint32_t)cmp;
         hp->hpet.timers[i].cmp = cmp;
+        /* Init hidden regs also */
+        hp->hpet.first_mc64[i] = 0;
+        hp->hpet.first_enabled[i] = 0;
     }
 #undef C
 
diff --git a/xen/include/asm-x86/hvm/vpt.h b/xen/include/asm-x86/hvm/vpt.h
index 41159d8..aea5121 100644
--- a/xen/include/asm-x86/hvm/vpt.h
+++ b/xen/include/asm-x86/hvm/vpt.h
@@ -87,6 +87,8 @@ struct hpet_registers {
     /* Hidden register state */
     uint64_t period[HPET_TIMER_NUM]; /* Last value written to comparator */
     uint64_t comparator64[HPET_TIMER_NUM]; /* 64 bit running comparator */
+    uint64_t first_mc64[HPET_TIMER_NUM]; /* 1st interval main counter */
+    uint8_t first_enabled[HPET_TIMER_NUM]; /* In 1st interval */
 };
 
 typedef struct HPETState {
-- 
1.8.4


_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxx
http://lists.xen.org/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.