[HVM] Clean up two small APIC TDCR issues.
authorkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 9 Nov 2006 17:53:05 +0000 (17:53 +0000)
committerkfraser@localhost.localdomain <kfraser@localhost.localdomain>
Thu, 9 Nov 2006 17:53:05 +0000 (17:53 +0000)
First, only save the bits that can be set, so that on a subsequent
read can't see MBZ bits as set. Next, be sure to initialize the
timer_divide_count, which is derived from the TDCR.  This avoids a
potential divide-by-zero elsewhere in the code.

The original patch was provided by Ben Thomas <ben@virtualiron.com>.
This modified version refactors the code slightly and renames
timer_divide_count to timer_divisor.

Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/vlapic.c
xen/include/asm-x86/hvm/vlapic.h

index 22888a76c78a5ffb260126b60b24ee5a27014442..9776c9dfff1f758a0b5340959cffe6ee2749d124 100644 (file)
@@ -495,8 +495,7 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
     else
         passed = now - vlapic->timer_last_update;
 
-    counter_passed = passed /
-      (APIC_BUS_CYCLE_NS * vlapic->timer_divide_count);
+    counter_passed = passed / (APIC_BUS_CYCLE_NS * vlapic->timer_divisor);
 
     tmcct -= counter_passed;
 
@@ -528,10 +527,21 @@ static uint32_t vlapic_get_tmcct(struct vlapic *vlapic)
     return tmcct;
 }
 
+static void vlapic_set_tdcr(struct vlapic *vlapic, unsigned int val)
+{
+    /* Only bits 0, 1 and 3 are settable; others are MBZ. */
+    val &= 0xb;
+    vlapic_set_reg(vlapic, APIC_TDCR, val);
+
+    /* Update the demangled timer_divisor. */
+    val = ((val & 3) | ((val & 8) >> 1)) + 1;
+    vlapic->timer_divisor = 1 << (val & 7);
+}
+
 static void vlapic_read_aligned(struct vlapic *vlapic, unsigned int offset,
                          unsigned int len, unsigned int *result)
 {
-    ASSERT(len == 4 && offset > 0 && offset <= APIC_TDCR);
+    ASSERT((len == 4) && (offset > 0) && (offset <= APIC_TDCR));
 
     *result = 0;
 
@@ -563,7 +573,7 @@ static unsigned long vlapic_read(struct vcpu *v, unsigned long address,
     struct vlapic *vlapic = vcpu_vlapic(v);
     unsigned int offset = address - vlapic->base_address;
 
-    if ( offset > APIC_TDCR)
+    if ( offset > APIC_TDCR )
         return 0;
 
     /* some bugs on kernel cause read this with byte*/
@@ -760,8 +770,7 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
         vlapic_set_reg(vlapic, APIC_TMCCT, val);
         vlapic->timer_last_update = now;
 
-        offset = APIC_BUS_CYCLE_NS *
-            vlapic->timer_divide_count * val;
+        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * val;
 
         set_timer(&vlapic->vlapic_timer, now + offset);
 
@@ -776,19 +785,10 @@ static void vlapic_write(struct vcpu *v, unsigned long address,
     break;
 
     case APIC_TDCR:
-    {
-        unsigned int tmp1, tmp2;
-
-        tmp1 = val & 0xf;
-        tmp2 = ((tmp1 & 0x3) | ((tmp1 & 0x8) >> 1)) + 1;
-        vlapic->timer_divide_count = 0x1 << (tmp2 & 0x7);
-
-        vlapic_set_reg(vlapic, APIC_TDCR, val);
-
-        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divide count is 0x%x",
-                    vlapic->timer_divide_count);
-    }
-    break;
+        vlapic_set_tdcr(vlapic, val & 0xb);
+        HVM_DBG_LOG(DBG_LEVEL_VLAPIC_TIMER, "timer divisor is 0x%x",
+                    vlapic->timer_divisor);
+        break;
 
     default:
         gdprintk(XENLOG_WARNING, 
@@ -852,8 +852,7 @@ void vlapic_timer_fn(void *data)
 
         vlapic_set_reg(vlapic, APIC_TMCCT, tmict);
 
-        offset = APIC_BUS_CYCLE_NS *
-                 vlapic->timer_divide_count * tmict;
+        offset = APIC_BUS_CYCLE_NS * vlapic->timer_divisor * tmict;
 
         set_timer(&vlapic->vlapic_timer, now + offset);
     }
@@ -967,6 +966,8 @@ static int vlapic_reset(struct vlapic *vlapic)
 
     vlapic->flush_tpr_threshold = 0;
 
+    vlapic_set_tdcr(vlapic, 0);
+
     vlapic->base_address = vlapic->apic_base_msr &
                            MSR_IA32_APICBASE_BASE;
 
index ed23916649ac08898a2feace7c8e7a782dbd662a..3720127d6d7bd3d1da1b438ff403945b7cd0524c 100644 (file)
@@ -49,7 +49,7 @@ struct vlapic {
     uint32_t           status;
     uint64_t           apic_base_msr;
     unsigned long      base_address;
-    uint32_t           timer_divide_count;
+    uint32_t           timer_divisor;
     struct timer       vlapic_timer;
     int                timer_pending_count;
     int                flush_tpr_threshold;