x86 hvm: When sending INIT-SIPI IPIs, pause the sending vcpu until the
authorKeir Fraser <keir@xen.org>
Wed, 20 Oct 2010 16:26:51 +0000 (17:26 +0100)
committerKeir Fraser <keir@xen.org>
Wed, 20 Oct 2010 16:26:51 +0000 (17:26 +0100)
asynchronous tasklet completes its work.

This is a little bit cleaner than busy-spinning in a retry loop.

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

index 3274d4deda038c4a3e7ee9935f3b3580be294532..3b94ca96a81456c07e8992b8c07603b348d18b63 100644 (file)
@@ -230,29 +230,29 @@ bool_t vlapic_match_dest(
 
 static void vlapic_init_sipi_action(unsigned long _vcpu)
 {
-    struct vcpu *v = (struct vcpu *)_vcpu;
-    struct domain *d = v->domain;
-    uint32_t icr = vcpu_vlapic(v)->init_sipi_tasklet_icr;
+    struct vcpu *origin = (struct vcpu *)_vcpu;
+    struct vcpu *target = vcpu_vlapic(origin)->init_sipi.target;
+    uint32_t icr = vcpu_vlapic(origin)->init_sipi.icr;
 
-    vcpu_pause(v);
+    vcpu_pause(target);
 
     switch ( icr & APIC_MODE_MASK )
     {
     case APIC_DM_INIT: {
         bool_t fpu_initialised;
-        domain_lock(d);
+        domain_lock(target->domain);
         /* Reset necessary VCPU state. This does not include FPU state. */
-        fpu_initialised = v->fpu_initialised;
-        vcpu_reset(v);
-        v->fpu_initialised = fpu_initialised;
-        vlapic_reset(vcpu_vlapic(v));
-        domain_unlock(d);
+        fpu_initialised = target->fpu_initialised;
+        vcpu_reset(target);
+        target->fpu_initialised = fpu_initialised;
+        vlapic_reset(vcpu_vlapic(target));
+        domain_unlock(target->domain);
         break;
     }
 
     case APIC_DM_STARTUP: {
         uint16_t reset_cs = (icr & 0xffu) << 8;
-        hvm_vcpu_reset_state(v, reset_cs, 0);
+        hvm_vcpu_reset_state(target, reset_cs, 0);
         break;
     }
 
@@ -260,13 +260,28 @@ static void vlapic_init_sipi_action(unsigned long _vcpu)
         BUG();
     }
 
-    vcpu_unpause(v);
+    vcpu_unpause(target);
+
+    vcpu_vlapic(origin)->init_sipi.target = NULL;
+    vcpu_unpause(origin);
 }
 
-static int vlapic_schedule_init_sipi_tasklet(struct vcpu *v, uint32_t icr)
+static int vlapic_schedule_init_sipi_tasklet(struct vcpu *target, uint32_t icr)
 {
-    vcpu_vlapic(v)->init_sipi_tasklet_icr = icr;
-    tasklet_schedule(&vcpu_vlapic(v)->init_sipi_tasklet);
+    struct vcpu *origin = current;
+
+    if ( vcpu_vlapic(origin)->init_sipi.target != NULL )
+    {
+        WARN(); /* should be impossible but don't BUG, just in case */
+        return X86EMUL_UNHANDLEABLE;
+    }
+
+    vcpu_pause_nosync(origin);
+
+    vcpu_vlapic(origin)->init_sipi.target = target;
+    vcpu_vlapic(origin)->init_sipi.icr = icr;
+    tasklet_schedule(&vcpu_vlapic(origin)->init_sipi.tasklet);
+
     return X86EMUL_RETRY;
 }
 
@@ -990,7 +1005,7 @@ int vlapic_init(struct vcpu *v)
     if ( v->vcpu_id == 0 )
         vlapic->hw.apic_base_msr |= MSR_IA32_APICBASE_BSP;
 
-    tasklet_init(&vlapic->init_sipi_tasklet,
+    tasklet_init(&vlapic->init_sipi.tasklet,
                  vlapic_init_sipi_action,
                  (unsigned long)v);
 
@@ -1001,7 +1016,7 @@ void vlapic_destroy(struct vcpu *v)
 {
     struct vlapic *vlapic = vcpu_vlapic(v);
 
-    tasklet_kill(&vlapic->init_sipi_tasklet);
+    tasklet_kill(&vlapic->init_sipi.tasklet);
     destroy_periodic_time(&vlapic->pt);
     unmap_domain_page_global(vlapic->regs);
     free_domheap_page(vlapic->regs_page);
index eda970f7808143b3571196670a0ff41edabe3642..905fff8daeef12e5028358cd318c725d2a5fb536 100644 (file)
@@ -59,8 +59,11 @@ struct vlapic {
     s_time_t                 timer_last_update;
     struct page_info         *regs_page;
     /* INIT-SIPI-SIPI work gets deferred to a tasklet. */
-    uint32_t                 init_sipi_tasklet_icr;
-    struct tasklet           init_sipi_tasklet;
+    struct {
+        struct vcpu          *target;
+        uint32_t             icr;
+        struct tasklet       tasklet;
+    } init_sipi;
 };
 
 static inline uint32_t vlapic_get_reg(struct vlapic *vlapic, uint32_t reg)