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

[Xen-devel] [RFC v1 13/15] Update Posted-Interrupts Descriptor during vCPU scheduling



The basic idea here is:
1. When vCPU's state is RUNSTATE_running,
        - set 'NV' to 'Notification Vector'.
        - Clear 'SN' to accpet PI.
        - set 'NDST' to the right pCPU.
2. When vCPU's state is RUNSTATE_blocked,
        - set 'NV' to 'Wake-up Vector', so we can wake up the
          related vCPU when posted-interrupt happens for it.
        - Clear 'SN' to accpet PI.
3. When vCPU's state is RUNSTATE_runnable/RUNSTATE_offline,
        - Set 'SN' to suppress non-urgent interrupts.
          (Current, we only support non-urgent interrupts)
        - Set 'NV' back to 'Notification Vector' if needed.

Signed-off-by: Feng Wu <feng.wu@xxxxxxxxx>
---
 xen/arch/x86/hvm/vmx/vmx.c | 108 +++++++++++++++++++++++++++++++++++++++++++++
 xen/common/schedule.c      |   3 ++
 2 files changed, 111 insertions(+)

diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c
index b30392c..6323bd6 100644
--- a/xen/arch/x86/hvm/vmx/vmx.c
+++ b/xen/arch/x86/hvm/vmx/vmx.c
@@ -1710,6 +1710,113 @@ static void vmx_handle_eoi(u8 vector)
     __vmwrite(GUEST_INTR_STATUS, status);
 }
 
+static void vmx_pi_desc_update(struct vcpu *v, int new_state)
+{
+    struct pi_desc *pi_desc = &v->arch.hvm_vmx.pi_desc;
+    struct pi_desc old, new;
+    int old_state = v->runstate.state;
+    unsigned long flags;
+
+    if ( !iommu_intpost )
+        return;
+
+    switch ( new_state )
+    {
+    case RUNSTATE_runnable:
+    case RUNSTATE_offline:
+        /*
+         * We don't need to send notification event to a non-running
+         * vcpu, the interrupt information will be delivered to it before
+         * VM-ENTRY when the vcpu is scheduled to run next time.
+         */
+        pi_set_sn(pi_desc);
+
+        /*
+         * If the state is transferred from RUNSTATE_blocked,
+         * we should set 'NV' feild back to posted_intr_vector,
+         * so the Posted-Interrupts can be delivered to the vCPU
+         * by VT-d HW after it is scheduled to run.
+         */
+        if ( old_state == RUNSTATE_blocked )
+        {
+            do
+            {
+                old.control = new.control = pi_desc->control;
+                new.nv = posted_intr_vector;
+            }
+            while ( cmpxchg(&pi_desc->control, old.control, new.control)
+                    != old.control );
+
+           /*
+            * Delete the vCPU from the related wakeup queue
+            * if we are resuming from blocked state
+            */
+           spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
+                             v->processor), flags);
+           list_del(&v->blocked_vcpu_list);
+           spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock,
+                                  v->processor), flags);
+        }
+        break;
+
+    case RUNSTATE_blocked:
+        /*
+         * The vCPU is blocked on the wait queue.
+         * Store the blocked vCPU on the list of the
+         * vcpu->wakeup_cpu, which is the destination
+         * of the wake-up notification event.
+         */
+        spin_lock_irqsave(&per_cpu(blocked_vcpu_on_cpu_lock,
+                          v->processor), flags);
+        list_add_tail(&v->blocked_vcpu_list,
+                      &per_cpu(blocked_vcpu_on_cpu, v->processor));
+        spin_unlock_irqrestore(&per_cpu(blocked_vcpu_on_cpu_lock,
+                               v->processor), flags);
+
+        do
+        {
+            old.control = new.control = pi_desc->control;
+
+            /*
+             * We should not block the vCPU if
+             * an interrupt is posted for it.
+             */
+
+            if ( pi_test_on(&old) == 1 )
+            {
+                tasklet_schedule(&v->vcpu_wakeup_tasklet);
+                return;
+            }
+
+            pi_clear_sn(&new);
+            new.nv = pi_wakeup_vector;
+        }
+        while ( cmpxchg(&pi_desc->control, old.control, new.control)
+                != old.control );
+        break;
+
+    case RUNSTATE_running:
+        ASSERT( pi_test_sn(pi_desc) == 1 );
+
+        do
+        {
+            old.control = new.control = pi_desc->control;
+            if ( x2apic_enabled )
+                new.ndst = cpu_physical_id(v->processor);
+            else
+                new.ndst = (cpu_physical_id(v->processor) << 8) & 0xFF00;
+
+            pi_clear_sn(&new);
+        }
+        while ( cmpxchg(&pi_desc->control, old.control, new.control)
+                != old.control );
+        break;
+
+    default:
+        break;
+    }
+}
+
 void vmx_hypervisor_cpuid_leaf(uint32_t sub_idx,
                                uint32_t *eax, uint32_t *ebx,
                                uint32_t *ecx, uint32_t *edx)
@@ -1795,6 +1902,7 @@ static struct hvm_function_table __initdata 
vmx_function_table = {
     .process_isr          = vmx_process_isr,
     .deliver_posted_intr  = vmx_deliver_posted_intr,
     .sync_pir_to_irr      = vmx_sync_pir_to_irr,
+    .pi_desc_update       = vmx_pi_desc_update,
     .handle_eoi           = vmx_handle_eoi,
     .nhvm_hap_walk_L1_p2m = nvmx_hap_walk_L1_p2m,
     .hypervisor_cpuid_leaf = vmx_hypervisor_cpuid_leaf,
diff --git a/xen/common/schedule.c b/xen/common/schedule.c
index ef79847..acf3186 100644
--- a/xen/common/schedule.c
+++ b/xen/common/schedule.c
@@ -157,6 +157,9 @@ static inline void vcpu_runstate_change(
         v->runstate.state_entry_time = new_entry_time;
     }
 
+    if ( is_hvm_vcpu(v) && hvm_funcs.pi_desc_update )
+        hvm_funcs.pi_desc_update(v, new_state);
+
     v->runstate.state = new_state;
 }
 
-- 
2.1.0


_______________________________________________
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®.