[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v4 21/28] vvtd: update hvm_gmsi_info when binding guest msi with pirq or
On Fri, Nov 17, 2017 at 02:22:28PM +0800, Chao Gao wrote: > ... handlding guest's invalidation request. > > To support pirq migration optimization and using VT-d posted interrupt to > inject msi from assigned devices, each time guest programs msi information > (affinity, vector), the struct hvm_gmsi_info should be updated accordingly. > But after introducing vvtd, guest only needs to update an IRTE, which is in > guest memory, to program msi information. vvtd doesn't trap r/w to the memory > range. Instead, it traps the queue invalidation, which is a method used to > notify VT-d hardware that an IRTE has changed. > > This patch updates hvm_gmsi_info structure and programs physical IRTEs to use > VT-d posted interrupt if possible when binding guest msi with pirq or handling > guest's invalidation request. For the latter, all physical interrupts bound > with the domain are gone through to find the ones matching with the IRTE. > > Notes: calling vvtd_process_iq() in vvtd_read() rather than in > vvtd_handle_irq_request() is to avoid ABBA deadlock of d->event_lock and > vvtd->ie_lock. > > Signed-off-by: Chao Gao <chao.gao@xxxxxxxxx> > Signed-off-by: Lan Tianyu <tianyu.lan@xxxxxxxxx> > --- > v4: > - new > --- > xen/arch/x86/hvm/hvm.c | 2 +- > xen/drivers/passthrough/io.c | 89 > ++++++++++++++++++++++++++++---------- > xen/drivers/passthrough/vtd/vvtd.c | 70 ++++++++++++++++++++++++++++-- > xen/include/asm-x86/hvm/hvm.h | 2 + > xen/include/asm-x86/hvm/irq.h | 1 + > xen/include/asm-x86/viommu.h | 11 +++++ > 6 files changed, 147 insertions(+), 28 deletions(-) > > diff --git a/xen/arch/x86/hvm/hvm.c b/xen/arch/x86/hvm/hvm.c > index 964418a..d2c1372 100644 > --- a/xen/arch/x86/hvm/hvm.c > +++ b/xen/arch/x86/hvm/hvm.c > @@ -462,7 +462,7 @@ void hvm_migrate_timers(struct vcpu *v) > pt_migrate(v); > } > > -static int hvm_migrate_pirq(struct domain *d, struct hvm_pirq_dpci > *pirq_dpci, > +int hvm_migrate_pirq(struct domain *d, struct hvm_pirq_dpci *pirq_dpci, > void *arg) > { > struct vcpu *v = arg; > diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c > index d8c66bf..9198ef5 100644 > --- a/xen/drivers/passthrough/io.c > +++ b/xen/drivers/passthrough/io.c > @@ -21,6 +21,7 @@ > #include <xen/iommu.h> > #include <xen/cpu.h> > #include <xen/irq.h> > +#include <xen/viommu.h> > #include <asm/hvm/irq.h> > #include <asm/hvm/support.h> > #include <asm/io_apic.h> > @@ -275,6 +276,61 @@ static struct vcpu *vector_hashing_dest(const struct > domain *d, > return dest; > } > > +void pt_update_gmsi(struct domain *d, struct hvm_pirq_dpci *pirq_dpci) > +{ > + uint8_t dest, delivery_mode; > + bool dest_mode; > + int dest_vcpu_id; > + const struct vcpu *vcpu; > + struct arch_irq_remapping_request request; > + struct arch_irq_remapping_info remap_info; > + > + ASSERT(spin_is_locked(&d->event_lock)); > + > + /* Calculate dest_vcpu_id for MSI-type pirq migration. */ > + irq_request_msi_fill(&request, pirq_dpci->gmsi.addr, > pirq_dpci->gmsi.data); > + if ( viommu_check_irq_remapping(d, &request) ) > + { > + /* An error in IRTE, don't perform the optimization */ > + if ( viommu_get_irq_info(d, &request, &remap_info) ) > + { > + pirq_dpci->gmsi.posted = false; > + pirq_dpci->gmsi.dest_vcpu_id = -1; > + pirq_dpci->gmsi.gvec = 0; > + return; > + } > + > + dest = remap_info.dest; > + dest_mode = remap_info.dest_mode; > + delivery_mode = remap_info.delivery_mode; > + pirq_dpci->gmsi.gvec = remap_info.vector; > + } > + else > + { > + dest = MASK_EXTR(pirq_dpci->gmsi.addr, MSI_ADDR_DEST_ID_MASK); > + dest_mode = pirq_dpci->gmsi.addr & MSI_ADDR_DESTMODE_MASK; > + delivery_mode = MASK_EXTR(pirq_dpci->gmsi.data, > + MSI_DATA_DELIVERY_MODE_MASK); > + pirq_dpci->gmsi.gvec = pirq_dpci->gmsi.data & MSI_DATA_VECTOR_MASK; > + } > + > + dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode); > + pirq_dpci->gmsi.dest_vcpu_id = dest_vcpu_id; > + > + pirq_dpci->gmsi.posted = false; > + vcpu = (dest_vcpu_id >= 0) ? d->vcpu[dest_vcpu_id] : NULL; So you use dest_vcpu_id to get the vcpu here... > + if ( iommu_intpost ) > + { > + if ( delivery_mode == dest_LowestPrio ) > + vcpu = vector_hashing_dest(d, dest, dest_mode, > pirq_dpci->gmsi.gvec); > + if ( vcpu ) > + { > + pirq_dpci->gmsi.posted = true; > + pirq_dpci->gmsi.dest_vcpu_id = vcpu->vcpu_id; ... which is only used here in order to get the dest_vcpu_id back. Is this really needed? Can't you just use dest_vcpu_id? I would rather do: if ( iommu_intpost && delivery_mode == dest_LowestPrio ) { const struct vcpu *vcpu = vector_hashing_dest(d, dest, dest_mode, pirq_dpci->gmsi.gvec); if ( vcpu ) { .... } } > + } > + } > +} > + > int pt_irq_create_bind( > struct domain *d, const struct xen_domctl_bind_pt_irq *pt_irq_bind) > { > @@ -339,9 +395,6 @@ int pt_irq_create_bind( > { > case PT_IRQ_TYPE_MSI: > { > - uint8_t dest, delivery_mode, gvec; > - bool dest_mode; > - int dest_vcpu_id; > const struct vcpu *vcpu; > > if ( !(pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) ) > @@ -411,35 +464,23 @@ int pt_irq_create_bind( > pirq_dpci->gmsi.addr = pt_irq_bind->u.msi.addr; > } > } > - /* Calculate dest_vcpu_id for MSI-type pirq migration. */ > - dest = MASK_EXTR(pirq_dpci->gmsi.addr, MSI_ADDR_DEST_ID_MASK); > - dest_mode = pirq_dpci->gmsi.addr & MSI_ADDR_DESTMODE_MASK; > - delivery_mode = MASK_EXTR(pirq_dpci->gmsi.data, > - MSI_DATA_DELIVERY_MODE_MASK); > - gvec = pirq_dpci->gmsi.data & MSI_DATA_VECTOR_MASK; > - pirq_dpci->gmsi.gvec = gvec; > > - dest_vcpu_id = hvm_girq_dest_2_vcpu_id(d, dest, dest_mode); > - pirq_dpci->gmsi.dest_vcpu_id = dest_vcpu_id; > + pt_update_gmsi(d, pirq_dpci); > spin_unlock(&d->event_lock); > > - pirq_dpci->gmsi.posted = false; > - vcpu = (dest_vcpu_id >= 0) ? d->vcpu[dest_vcpu_id] : NULL; > - if ( iommu_intpost ) > - { > - if ( delivery_mode == dest_LowestPrio ) > - vcpu = vector_hashing_dest(d, dest, dest_mode, > - pirq_dpci->gmsi.gvec); > - if ( vcpu ) > - pirq_dpci->gmsi.posted = true; > - } > - if ( dest_vcpu_id >= 0 ) > - hvm_migrate_pirqs(d->vcpu[dest_vcpu_id]); > + if ( pirq_dpci->gmsi.dest_vcpu_id >= 0 ) > + hvm_migrate_pirqs(d->vcpu[pirq_dpci->gmsi.dest_vcpu_id]); > > /* Use interrupt posting if it is supported. */ > if ( iommu_intpost ) > + { > + if ( pirq_dpci->gmsi.posted ) > + vcpu = d->vcpu[pirq_dpci->gmsi.dest_vcpu_id]; > + else > + vcpu = NULL; > pi_update_irte(vcpu ? &vcpu->arch.hvm_vmx.pi_desc : NULL, > info, pirq_dpci->gmsi.gvec); If vcpu is now only used inside of this if condition please move it's declaration here to reduce the scope. > + } > > if ( pt_irq_bind->u.msi.gflags & XEN_DOMCTL_VMSI_X86_UNMASKED ) > { > diff --git a/xen/drivers/passthrough/vtd/vvtd.c > b/xen/drivers/passthrough/vtd/vvtd.c > index f6bde69..d12ad1d 100644 > --- a/xen/drivers/passthrough/vtd/vvtd.c > +++ b/xen/drivers/passthrough/vtd/vvtd.c > @@ -477,6 +477,50 @@ static int vvtd_record_fault(struct vvtd *vvtd, > } > > /* > + * 'arg' is the index of interrupt remapping table. This index is used to > + * search physical irqs which satify that the gmsi mapped with the physical > irq > + * is tranlated by the IRTE refered to by the index. The struct hvm_gmsi_info > + * contains some fields are infered from an virtual IRTE. These fields should > + * be updated when guest invalidates an IRTE. Furthermore, the physical IRTE > + * is updated accordingly to reduce IPIs or utilize VT-d posted interrupt. > + * > + * if 'arg' is -1, perform a global invalidation. > + */ > +static int invalidate_gmsi(struct domain *d, struct hvm_pirq_dpci *pirq_dpci, > + void *arg) > +{ > + if ( pirq_dpci->flags & HVM_IRQ_DPCI_GUEST_MSI ) > + { > + uint32_t index, target = (long)arg; > + struct arch_irq_remapping_request req; > + const struct vcpu *vcpu; > + > + irq_request_msi_fill(&req, pirq_dpci->gmsi.addr, > pirq_dpci->gmsi.data); > + if ( !irq_remapping_request_index(&req, &index) && > + ((target == -1) || (target == index)) ) Shouldn't this -1 be some kind of define, like GMSI_ALL or similar? Also isn't it possible to use -1 as a valid target? > + { > + pt_update_gmsi(d, pirq_dpci); > + if ( pirq_dpci->gmsi.dest_vcpu_id >= 0 ) > + hvm_migrate_pirq(d, pirq_dpci, > + d->vcpu[pirq_dpci->gmsi.dest_vcpu_id]); > + > + /* Use interrupt posting if it is supported. */ > + if ( iommu_intpost ) > + { > + if ( pirq_dpci->gmsi.posted ) > + vcpu = d->vcpu[pirq_dpci->gmsi.dest_vcpu_id]; > + else > + vcpu = NULL; > + pi_update_irte(vcpu ? &vcpu->arch.hvm_vmx.pi_desc : NULL, > + dpci_pirq(pirq_dpci), pirq_dpci->gmsi.gvec); > + } > + } > + } > + > + return 0; > +} > + > +/* > * Process an invalidation descriptor. Currently, only two types descriptors, > * Interrupt Entry Cache Invalidation Descritor and Invalidation Wait > * Descriptor are handled. > @@ -530,7 +574,26 @@ static int process_iqe(struct vvtd *vvtd, uint32_t i) > break; > > case TYPE_INVAL_IEC: > - /* No cache is preserved in vvtd, nothing is needed to be flushed */ > + /* > + * If VT-d pi is enabled, pi_update_irte() may be called. It assumes > + * pcidevs_locked(). > + */ > + pcidevs_lock(); > + spin_lock(&vvtd->domain->event_lock); > + /* A global invalidation of the cache is requested */ > + if ( !qinval.q.iec_inv_dsc.lo.granu ) > + pt_pirq_iterate(vvtd->domain, invalidate_gmsi, (void *)(long)-1); > + else > + { > + uint32_t iidx = qinval.q.iec_inv_dsc.lo.iidx; > + uint32_t nr = 1 << qinval.q.iec_inv_dsc.lo.im; > + > + for ( ; nr; nr--, iidx++) You can initialize nr in the for loop. > + pt_pirq_iterate(vvtd->domain, invalidate_gmsi, > + (void *)(long)iidx); > + } > + spin_unlock(&vvtd->domain->event_lock); > + pcidevs_unlock(); > break; > > default: > @@ -839,6 +902,8 @@ static int vvtd_read(struct vcpu *v, unsigned long addr, > else > *pval = vvtd_get_reg_quad(vvtd, offset); > > + if ( !atomic_read(&vvtd->inflight_intr) ) > + vvtd_process_iq(vvtd); > return X86EMUL_OKAY; > } > > @@ -1088,8 +1153,7 @@ static int vvtd_handle_irq_request(const struct domain > *d, > irte.remap.tm); > > out: > - if ( !atomic_dec_and_test(&vvtd->inflight_intr) ) > - vvtd_process_iq(vvtd); > + atomic_dec(&vvtd->inflight_intr); Why is this removed? It was changed like 4 patches before, and reverted here. > return ret; > } > > diff --git a/xen/include/asm-x86/hvm/hvm.h b/xen/include/asm-x86/hvm/hvm.h > index b687e03..f276ab6 100644 > --- a/xen/include/asm-x86/hvm/hvm.h > +++ b/xen/include/asm-x86/hvm/hvm.h > @@ -394,6 +394,8 @@ bool hvm_set_guest_bndcfgs(struct vcpu *v, u64 val); > bool hvm_check_cpuid_faulting(struct vcpu *v); > void hvm_migrate_timers(struct vcpu *v); > void hvm_do_resume(struct vcpu *v); > +int hvm_migrate_pirq(struct domain *d, struct hvm_pirq_dpci *pirq_dpci, > + void *arg); Please align. Thanks, Roger. _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |