[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] [Xen-devel] [RFC v2 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 | 130 +++++++++++++++++++++++++++++++++++++++++++++ xen/common/schedule.c | 5 ++ xen/include/xen/sched.h | 2 + 3 files changed, 137 insertions(+) diff --git a/xen/arch/x86/hvm/vmx/vmx.c b/xen/arch/x86/hvm/vmx/vmx.c index 556a584..cdcc012 100644 --- a/xen/arch/x86/hvm/vmx/vmx.c +++ b/xen/arch/x86/hvm/vmx/vmx.c @@ -1711,6 +1711,131 @@ static void vmx_handle_eoi(u8 vector) __vmwrite(GUEST_INTR_STATUS, status); } +static void vmx_pi_desc_update(struct vcpu *v, int old_state) +{ + struct pi_desc *pi_desc = &v->arch.hvm_vmx.pi_desc; + struct pi_desc old, new; + unsigned long flags; + + if ( !iommu_intpost ) + return; + + switch ( v->runstate.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_desc->sn = 1; + + /* + * 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 block list + * if we are resuming from blocked state + */ + spin_lock_irqsave(&per_cpu(blocked_vcpu_lock, + v->pre_pcpu), flags); + list_del(&v->blocked_vcpu_list); + spin_unlock_irqrestore(&per_cpu(blocked_vcpu_lock, + v->pre_pcpu), flags); + } + break; + + case RUNSTATE_blocked: + /* + * The vCPU is blocked on the block list. + * Add the blocked vCPU on the list of the + * vcpu->pre_pcpu, which is the destination + * of the wake-up notification event. + */ + v->pre_pcpu = v->processor; + spin_lock_irqsave(&per_cpu(blocked_vcpu_lock, + v->pre_pcpu), flags); + list_add_tail(&v->blocked_vcpu_list, + &per_cpu(blocked_vcpu, v->pre_pcpu)); + spin_unlock_irqrestore(&per_cpu(blocked_vcpu_lock, + v->pre_pcpu), flags); + + do + { + old.control = new.control = pi_desc->control; + + /* + * We should not block the vCPU if + * an interrupt was posted for it. + */ + + if ( old.on == 1 ) + { + /* + * The vCPU will be removed from the block list + * during its state transferring from RUNSTATE_blocked + * to RUNSTATE_runnable after the following tasklet + * is scheduled to run. + */ + tasklet_schedule(&v->vcpu_wakeup_tasklet); + return; + } + + /* + * Change the 'NDST' field to v->pre_pcpu, so when + * external interrupts from assigned deivces happen, + * wakeup notifiction event will go to v->pre_pcpu, + * then in pi_wakeup_interrupt() we can find the + * vCPU in the right list to wake up. + */ + if ( x2apic_enabled ) + new.ndst = cpu_physical_id(v->pre_pcpu); + else + new.ndst = MASK_INSR(cpu_physical_id(v->pre_pcpu), + PI_xAPIC_NDST_MASK); + new.sn = 0; + new.nv = pi_wakeup_vector; + } + while ( cmpxchg(&pi_desc->control, old.control, new.control) + != old.control ); + break; + + case RUNSTATE_running: + ASSERT( pi_desc->sn == 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; + + new.sn = 0; + } + 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) @@ -1842,7 +1967,12 @@ const struct hvm_function_table * __init start_vmx(void) alloc_direct_apic_vector(&posted_intr_vector, pi_notification_interrupt); if ( iommu_intpost ) + { alloc_direct_apic_vector(&pi_wakeup_vector, pi_wakeup_interrupt); + vmx_function_table.pi_desc_update = vmx_pi_desc_update; + } + else + vmx_function_table.pi_desc_update = NULL; } else { diff --git a/xen/common/schedule.c b/xen/common/schedule.c index 88770c6..3c6b2e1 100644 --- a/xen/common/schedule.c +++ b/xen/common/schedule.c @@ -142,6 +142,7 @@ static inline void vcpu_runstate_change( struct vcpu *v, int new_state, s_time_t new_entry_time) { s_time_t delta; + int old_state; ASSERT(v->runstate.state != new_state); ASSERT(spin_is_locked(per_cpu(schedule_data,v->processor).schedule_lock)); @@ -157,7 +158,11 @@ static inline void vcpu_runstate_change( v->runstate.state_entry_time = new_entry_time; } + old_state = v->runstate.state; v->runstate.state = new_state; + + if ( is_hvm_vcpu(v) && hvm_funcs.pi_desc_update ) + hvm_funcs.pi_desc_update(v, old_state); } void vcpu_runstate_get(struct vcpu *v, struct vcpu_runstate_info *runstate) diff --git a/xen/include/xen/sched.h b/xen/include/xen/sched.h index 4a7e6b3..71d228a 100644 --- a/xen/include/xen/sched.h +++ b/xen/include/xen/sched.h @@ -142,6 +142,8 @@ struct vcpu int processor; + int pre_pcpu; + vcpu_info_t *vcpu_info; struct domain *domain; -- 2.1.0 _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxx http://lists.xen.org/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |