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

[Xen-changelog] [xen-unstable] [HVM] vlapic: More cleanups, simplifications and fixes.



# HG changeset patch
# User kfraser@xxxxxxxxxxxxxxxxxxxxx
# Node ID e0dc5a544ea1e84e6d3f9de916e401e06529ad72
# Parent  5b97dafc7448f645313ef244ca77a4c47bf264e1
[HVM] vlapic: More cleanups, simplifications and fixes.
Signed-off-by: Keir Fraser <keir@xxxxxxxxxxxxx>
---
 xen/arch/x86/hvm/svm/svm.c       |    2 
 xen/arch/x86/hvm/vlapic.c        |  166 +++++++++++++++++----------------------
 xen/arch/x86/hvm/vmx/io.c        |   19 ++--
 xen/arch/x86/hvm/vmx/vmx.c       |    2 
 xen/include/asm-x86/hvm/vlapic.h |   27 +++---
 5 files changed, 100 insertions(+), 116 deletions(-)

diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/svm/svm.c
--- a/xen/arch/x86/hvm/svm/svm.c        Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/svm/svm.c        Tue Nov 14 10:44:16 2006 +0000
@@ -990,7 +990,7 @@ static void svm_vmexit_do_cpuid(struct v
         cpuid(input, &eax, &ebx, &ecx, &edx);       
         if (input == 0x00000001 || input == 0x80000001 )
         {
-            if ( !vlapic_global_enabled(vcpu_vlapic(v)) )
+            if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
             {
                 /* Since the apic is disabled, avoid any confusion 
                    about SMP cpus being available */
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vlapic.c
--- a/xen/arch/x86/hvm/vlapic.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vlapic.c Tue Nov 14 10:44:16 2006 +0000
@@ -71,17 +71,22 @@ static unsigned int vlapic_lvt_mask[VLAP
 #define APIC_DEST_NOSHORT                0x0
 #define APIC_DEST_MASK                   0x800
 
-#define vlapic_lvt_enabled(vlapic, lvt_type)    \
+#define vlapic_lvt_enabled(vlapic, lvt_type)                    \
     (!(vlapic_get_reg(vlapic, lvt_type) & APIC_LVT_MASKED))
 
-#define vlapic_lvt_vector(vlapic, lvt_type)     \
+#define vlapic_lvt_vector(vlapic, lvt_type)                     \
     (vlapic_get_reg(vlapic, lvt_type) & APIC_VECTOR_MASK)
 
-#define vlapic_lvt_dm(vlapic, lvt_type)           \
+#define vlapic_lvt_dm(vlapic, lvt_type)                         \
     (vlapic_get_reg(vlapic, lvt_type) & APIC_MODE_MASK)
 
-#define vlapic_lvtt_period(vlapic)     \
+#define vlapic_lvtt_period(vlapic)                              \
     (vlapic_get_reg(vlapic, APIC_LVTT) & APIC_LVT_TIMER_PERIODIC)
+
+#define vlapic_base_address(vlapic)                             \
+    (vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE)
+
+static int vlapic_reset(struct vlapic *vlapic);
 
 /*
  * Generic APIC bitmap vector update & search routines.
@@ -238,8 +243,7 @@ static int vlapic_match_dest(struct vcpu
         if ( dest_mode == 0 )
         {
             /* Physical mode. */
-            if ( (dest == 0xFF) || /* broadcast? */
-                 (GET_APIC_ID(vlapic_get_reg(target, APIC_ID)) == dest) )
+            if ( (dest == 0xFF) || (dest == v->vcpu_id) )
                 result = 1;
         }
         else
@@ -283,7 +287,7 @@ static int vlapic_accept_irq(struct vcpu
     case APIC_DM_FIXED:
     case APIC_DM_LOWEST:
         /* FIXME add logic for vcpu on reset */
-        if ( unlikely(vlapic == NULL || !vlapic_enabled(vlapic)) )
+        if ( unlikely(!vlapic_enabled(vlapic)) )
             break;
 
         if ( vlapic_test_and_set_irr(vector, vlapic) && trig_mode )
@@ -319,7 +323,7 @@ static int vlapic_accept_irq(struct vcpu
         if ( trig_mode && !(level & APIC_INT_ASSERT) )
             break;
         /* FIXME How to check the situation after vcpu reset? */
-        if ( test_and_clear_bit(_VCPUF_initialised, &v->vcpu_flags) )
+        if ( test_bit(_VCPUF_initialised, &v->vcpu_flags) )
         {
             gdprintk(XENLOG_ERR, "Reset hvm vcpu not supported yet\n");
             goto exit_and_crash;
@@ -371,21 +375,15 @@ struct vlapic *apic_round_robin(
 
     old = next = d->arch.hvm_domain.round_info[vector];
 
-    /* the vcpu array is arranged according to vcpu_id */
     do {
         if ( ++next == MAX_VIRT_CPUS ) 
             next = 0;
-        if ( (d->vcpu[next] == NULL) ||
-             !test_bit(_VCPUF_initialised, &d->vcpu[next]->vcpu_flags) )
+        if ( (d->vcpu[next] == NULL) || !test_bit(next, &bitmap) )
             continue;
-
-        if ( test_bit(next, &bitmap) )
-        {
-            target = vcpu_vlapic(d->vcpu[next]);
-            if ( vlapic_enabled(target) )
-                break;
-            target = NULL;
-        }
+        target = vcpu_vlapic(d->vcpu[next]);
+        if ( vlapic_enabled(target) )
+            break;
+        target = NULL;
     } while ( next != old );
 
     d->arch.hvm_domain.round_info[vector] = next;
@@ -398,10 +396,9 @@ void vlapic_EOI_set(struct vlapic *vlapi
 {
     int vector = vlapic_find_highest_isr(vlapic);
 
-    /* Not every write EOI will has correpsoning ISR,
-       one example is when Kernel check timer on setup_IO_APIC */
+    /* Some EOI writes may not have a matching to an in-service interrupt. */
     if ( vector == -1 )
-        return ;
+        return;
 
     vlapic_clear_vector(vector, vlapic->regs + APIC_ISR);
 
@@ -538,7 +535,7 @@ static unsigned long vlapic_read(struct 
     unsigned int tmp;
     unsigned long result;
     struct vlapic *vlapic = vcpu_vlapic(v);
-    unsigned int offset = address - vlapic->base_address;
+    unsigned int offset = address - vlapic_base_address(vlapic);
 
     if ( offset > APIC_TDCR )
         return 0;
@@ -588,7 +585,7 @@ static void vlapic_write(struct vcpu *v,
                          unsigned long len, unsigned long val)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
-    unsigned int offset = address - vlapic->base_address;
+    unsigned int offset = address - vlapic_base_address(vlapic);
 
     if ( offset != 0xb0 )
         HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
@@ -641,10 +638,6 @@ static void vlapic_write(struct vcpu *v,
 
     switch ( offset )
     {
-    case APIC_ID:   /* Local APIC ID */
-        vlapic_set_reg(vlapic, APIC_ID, val);
-        break;
-
     case APIC_TASKPRI:
         vlapic_set_reg(vlapic, APIC_TASKPRI, val & 0xff);
         vlapic->flush_tpr_threshold = 1;
@@ -670,7 +663,7 @@ static void vlapic_write(struct vcpu *v,
             int i;
             uint32_t lvt_val;
 
-            vlapic->status |= VLAPIC_SOFTWARE_DISABLE_MASK;
+            vlapic->disabled |= VLAPIC_SW_DISABLED;
 
             for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
             {
@@ -678,17 +671,11 @@ static void vlapic_write(struct vcpu *v,
                 vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i,
                                lvt_val | APIC_LVT_MASKED);
             }
-
-            if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
-                 == APIC_DM_EXTINT )
-                clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
         }
         else
         {
-            vlapic->status &= ~VLAPIC_SOFTWARE_DISABLE_MASK;
-            if ( (vlapic_get_reg(vlapic, APIC_LVT0) & APIC_MODE_MASK)
-                  == APIC_DM_EXTINT )
-                set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
+            vlapic->disabled &= ~VLAPIC_SW_DISABLED;
+            vlapic->flush_tpr_threshold = 1;
         }
         break;
 
@@ -712,26 +699,11 @@ static void vlapic_write(struct vcpu *v,
     case APIC_LVT0:         /* LVT LINT0 Reg */
     case APIC_LVT1:         /* LVT Lint1 Reg */
     case APIC_LVTERR:       /* LVT Error Reg */
-    {
-        if ( vlapic->status & VLAPIC_SOFTWARE_DISABLE_MASK )
+        if ( vlapic_sw_disabled(vlapic) )
             val |= APIC_LVT_MASKED;
-
         val &= vlapic_lvt_mask[(offset - APIC_LVTT) >> 4];
-
         vlapic_set_reg(vlapic, offset, val);
-
-        if ( (vlapic_vcpu(vlapic)->vcpu_id == 0) && (offset == APIC_LVT0) )
-        {
-            if ( (val & APIC_MODE_MASK) == APIC_DM_EXTINT )
-                if ( val & APIC_LVT_MASKED)
-                    clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
-                else
-                    set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
-            else
-                clear_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
-        }
-    }
-    break;
+        break;
 
     case APIC_TMICT:
     {
@@ -773,10 +745,8 @@ static int vlapic_range(struct vcpu *v, 
 static int vlapic_range(struct vcpu *v, unsigned long addr)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
-
-    return (vlapic_global_enabled(vlapic) &&
-            (addr >= vlapic->base_address) &&
-            (addr < vlapic->base_address + PAGE_SIZE));
+    unsigned long offset  = addr - vlapic_base_address(vlapic);
+    return (!vlapic_hw_disabled(vlapic) && (offset < PAGE_SIZE));
 }
 
 struct hvm_mmio_handler vlapic_mmio_handler = {
@@ -787,17 +757,23 @@ struct hvm_mmio_handler vlapic_mmio_hand
 
 void vlapic_msr_set(struct vlapic *vlapic, uint64_t value)
 {
+    if ( (vlapic->apic_base_msr ^ value) & MSR_IA32_APICBASE_ENABLE )
+    {
+        if ( value & MSR_IA32_APICBASE_ENABLE )
+        {
+            vlapic_reset(vlapic);
+            vlapic->disabled &= ~VLAPIC_HW_DISABLED;
+        }
+        else
+        {
+            vlapic->disabled |= VLAPIC_HW_DISABLED;
+        }
+    }
+
     vlapic->apic_base_msr = value;
-    vlapic->base_address  = vlapic->apic_base_msr & MSR_IA32_APICBASE_BASE;
-
-    if ( !(value & MSR_IA32_APICBASE_ENABLE) )
-        set_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status );
-    else
-        clear_bit(_VLAPIC_GLOB_DISABLE, &vlapic->status);
 
     HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
-                "apic base msr is 0x%016"PRIx64", and base address is 0x%lx.",
-                vlapic->apic_base_msr, vlapic->base_address);
+                "apic base msr is 0x%016"PRIx64".", vlapic->apic_base_msr);
 }
 
 void vlapic_timer_fn(void *data)
@@ -845,8 +821,15 @@ int vlapic_accept_pic_intr(struct vcpu *
 int vlapic_accept_pic_intr(struct vcpu *v)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
-
-    return vlapic ? test_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status) : 1;
+    uint32_t lvt0 = vlapic_get_reg(vlapic, APIC_LVT0);
+
+    /*
+     * Only CPU0 is wired to the 8259A. INTA cycles occur if LINT0 is set up
+     * accept ExtInts, or if the LAPIC is disabled (so LINT0 behaves as INTR).
+     */
+    return ((v->vcpu_id == 0) &&
+            (((lvt0 & (APIC_MODE_MASK|APIC_LVT_MASKED)) == APIC_DM_EXTINT) ||
+             vlapic_hw_disabled(vlapic)));
 }
 
 int cpu_get_apic_interrupt(struct vcpu *v, int *mode)
@@ -854,7 +837,7 @@ int cpu_get_apic_interrupt(struct vcpu *
     struct vlapic *vlapic = vcpu_vlapic(v);
     int highest_irr;
 
-    if ( !vlapic || !vlapic_enabled(vlapic) )
+    if ( !vlapic_enabled(vlapic) )
         return -1;
 
     highest_irr = vlapic_find_highest_irr(vlapic);
@@ -886,9 +869,6 @@ void vlapic_post_injection(struct vcpu *
 void vlapic_post_injection(struct vcpu *v, int vector, int deliver_mode)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
-
-    if ( unlikely(vlapic == NULL) )
-        return;
 
     switch ( deliver_mode )
     {
@@ -920,36 +900,38 @@ void vlapic_post_injection(struct vcpu *
     }
 }
 
+/* Reset the VLPAIC back to its power-on/reset state. */
 static int vlapic_reset(struct vlapic *vlapic)
 {
     struct vcpu *v = vlapic_vcpu(vlapic);
     int i;
 
-    vlapic_set_reg(vlapic, APIC_ID, v->vcpu_id << 24);
-
+    vlapic_set_reg(vlapic, APIC_ID,  v->vcpu_id << 24);
     vlapic_set_reg(vlapic, APIC_LVR, VLAPIC_VERSION);
+
+    for ( i = 0; i < 8; i++ )
+    {
+        vlapic_set_reg(vlapic, APIC_IRR + 0x10 * i, 0);
+        vlapic_set_reg(vlapic, APIC_ISR + 0x10 * i, 0);
+        vlapic_set_reg(vlapic, APIC_TMR + 0x10 * i, 0);
+    }
+    vlapic_set_reg(vlapic, APIC_ICR,     0);
+    vlapic_set_reg(vlapic, APIC_ICR2,    0);
+    vlapic_set_reg(vlapic, APIC_LDR,     0);
+    vlapic_set_reg(vlapic, APIC_TASKPRI, 0);
+    vlapic_set_reg(vlapic, APIC_TMICT,   0);
+    vlapic_set_reg(vlapic, APIC_TMCCT,   0);
+    vlapic_set_tdcr(vlapic, 0);
+
+    vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
 
     for ( i = 0; i < VLAPIC_LVT_NUM; i++ )
         vlapic_set_reg(vlapic, APIC_LVTT + 0x10 * i, APIC_LVT_MASKED);
 
-    vlapic_set_reg(vlapic, APIC_DFR, 0xffffffffU);
-
     vlapic_set_reg(vlapic, APIC_SPIV, 0xff);
-
-    vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
-
-    vlapic->flush_tpr_threshold = 0;
-
-    vlapic_set_tdcr(vlapic, 0);
-
-    vlapic->base_address = vlapic->apic_base_msr &
-                           MSR_IA32_APICBASE_BASE;
-
-    HVM_DBG_LOG(DBG_LEVEL_VLAPIC,
-                "vcpu=%p, id=%d, vlapic_apic_base_msr=0x%016"PRIx64", "
-                "base_address=0x%0lx.",
-                v,  GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)),
-                vlapic->apic_base_msr, vlapic->base_address);
+    vlapic->disabled |= VLAPIC_SW_DISABLED;
+
+    vlapic->flush_tpr_threshold = 1;
 
     return 1;
 }
@@ -974,6 +956,7 @@ int vlapic_init(struct vcpu *v)
 
     vlapic_reset(vlapic);
 
+    vlapic->apic_base_msr = MSR_IA32_APICBASE_ENABLE | APIC_DEFAULT_PHYS_BASE;
     if ( v->vcpu_id == 0 )
         vlapic->apic_base_msr |= MSR_IA32_APICBASE_BSP;
 
@@ -986,7 +969,6 @@ int vlapic_init(struct vcpu *v)
     {
         vlapic_set_reg(vlapic, APIC_LVT0, APIC_MODE_EXTINT << 8);
         vlapic_set_reg(vlapic, APIC_LVT1, APIC_MODE_NMI << 8);
-        set_bit(_VLAPIC_BSP_ACCEPT_PIC, &vlapic->status);
     }
 #endif
 
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vmx/io.c
--- a/xen/arch/x86/hvm/vmx/io.c Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vmx/io.c Tue Nov 14 10:44:16 2006 +0000
@@ -69,20 +69,21 @@ static inline int is_interruptibility_st
 #ifdef __x86_64__
 static void update_tpr_threshold(struct vlapic *vlapic)
 {
-    int highest_irr, tpr;
+    int max_irr, tpr;
 
     /* Clear the work-to-do flag /then/ do the work. */
     vlapic->flush_tpr_threshold = 0;
     mb();
 
-    highest_irr = vlapic_find_highest_irr(vlapic);
+    if ( !vlapic_enabled(vlapic) || 
+         ((max_irr = vlapic_find_highest_irr(vlapic)) == -1) )
+    {
+        __vmwrite(TPR_THRESHOLD, 0);
+        return;
+    }
+
     tpr = vlapic_get_reg(vlapic, APIC_TASKPRI) & 0xF0;
-
-    if ( highest_irr == -1 )
-        __vmwrite(TPR_THRESHOLD, 0);
-    else
-        __vmwrite(TPR_THRESHOLD,
-                  (highest_irr > tpr) ? (tpr >> 4) : (highest_irr >> 4));
+    __vmwrite(TPR_THRESHOLD, (max_irr > tpr) ? (tpr >> 4) : (max_irr >> 4));
 }
 #else
 #define update_tpr_threshold(v) ((void)0)
@@ -115,7 +116,7 @@ asmlinkage void vmx_intr_assist(void)
             pic_set_xen_irq(pic, callback_irq, local_events_need_delivery());
     }
 
-    if ( vlapic_enabled(vlapic) && vlapic->flush_tpr_threshold )
+    if ( vlapic->flush_tpr_threshold )
         update_tpr_threshold(vlapic);
 
     has_ext_irq = cpu_has_pending_irq(v);
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/arch/x86/hvm/vmx/vmx.c
--- a/xen/arch/x86/hvm/vmx/vmx.c        Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/arch/x86/hvm/vmx/vmx.c        Tue Nov 14 10:44:16 2006 +0000
@@ -853,7 +853,7 @@ static void vmx_do_cpuid(struct cpu_user
             /* Mask off reserved bits. */
             ecx &= ~VMX_VCPU_CPUID_L1_ECX_RESERVED;
 
-            if ( !vlapic_global_enabled(vcpu_vlapic(v)) )
+            if ( vlapic_hw_disabled(vcpu_vlapic(v)) )
                 clear_bit(X86_FEATURE_APIC, &edx);
     
 #if CONFIG_PAGING_LEVELS >= 3
diff -r 5b97dafc7448 -r e0dc5a544ea1 xen/include/asm-x86/hvm/vlapic.h
--- a/xen/include/asm-x86/hvm/vlapic.h  Mon Nov 13 17:23:49 2006 -0700
+++ b/xen/include/asm-x86/hvm/vlapic.h  Tue Nov 14 10:44:16 2006 +0000
@@ -33,22 +33,23 @@
 #define VLAPIC_ID(vlapic)   \
     (GET_APIC_ID(vlapic_get_reg(vlapic, APIC_ID)))
 
-#define _VLAPIC_GLOB_DISABLE            0x0
-#define VLAPIC_GLOB_DISABLE_MASK        0x1
-#define VLAPIC_SOFTWARE_DISABLE_MASK    0x2
-#define _VLAPIC_BSP_ACCEPT_PIC          0x3
-
-#define vlapic_enabled(vlapic)              \
-    (!((vlapic)->status &                   \
-       (VLAPIC_GLOB_DISABLE_MASK | VLAPIC_SOFTWARE_DISABLE_MASK)))
-
-#define vlapic_global_enabled(vlapic)       \
-    (!(test_bit(_VLAPIC_GLOB_DISABLE, &(vlapic)->status)))
+/*
+ * APIC can be disabled in two ways:
+ *  1. 'Hardware disable': via IA32_APIC_BASE_MSR[11]
+ *     CPU should behave as if it does not have an APIC.
+ *  2. 'Software disable': via APIC_SPIV[8].
+ *     APIC is visible but does not respond to interrupt messages.
+ */
+#define VLAPIC_HW_DISABLED              0x1
+#define VLAPIC_SW_DISABLED              0x2
+#define vlapic_sw_disabled(vlapic)  ((vlapic)->disabled & VLAPIC_SW_DISABLED)
+#define vlapic_hw_disabled(vlapic)  ((vlapic)->disabled & VLAPIC_HW_DISABLED)
+#define vlapic_disabled(vlapic)     ((vlapic)->disabled)
+#define vlapic_enabled(vlapic)      (!vlapic_disabled(vlapic))
 
 struct vlapic {
-    uint32_t           status;
     uint64_t           apic_base_msr;
-    unsigned long      base_address;
+    uint32_t           disabled; /* VLAPIC_xx_DISABLED */
     uint32_t           timer_divisor;
     struct timer       vlapic_timer;
     int                timer_pending_count;

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

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