[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index] Re: [Xen-devel] [PATCH v2] x86/passthrough: fix migration of MSI when using posted interrupts
Hi Roger & Jan, I got my test env back, and back the patch to stable-4.12, run same test, I still seen original issue, guest kernel printed error: kernel:do_IRQ: 20.114 No irq handler for vector (irq -1) After that, pass through infiniband VF stopped to work. My patch as below, please check: diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c index a1a43cd792..2d175d2a00 100644 --- a/xen/arch/x86/hvm/vlapic.c +++ b/xen/arch/x86/hvm/vlapic.c @@ -111,6 +111,12 @@ static void vlapic_clear_irr(int vector, struct vlapic *vlapic) vlapic_clear_vector(vector, &vlapic->regs->data[APIC_IRR]); } +void vlapic_sync_pir_to_irr(struct vcpu *v) +{ + if ( hvm_funcs.sync_pir_to_irr ) + hvm_funcs.sync_pir_to_irr(v); +} + static int vlapic_find_highest_irr(struct vlapic *vlapic) { if ( hvm_funcs.sync_pir_to_irr ) diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c index 4290c7c710..b628adea4c 100644 --- a/xen/drivers/passthrough/io.c +++ b/xen/drivers/passthrough/io.c @@ -341,7 +341,7 @@ int pt_irq_create_bind( { uint8_t dest, delivery_mode; bool dest_mode; - int dest_vcpu_id; + int dest_vcpu_id, prev_vcpu_id = -1; const struct vcpu *vcpu; uint32_t gflags = pt_irq_bind->u.msi.gflags & ~XEN_DOMCTL_VMSI_X86_UNMASKED; @@ -411,6 +411,7 @@ int pt_irq_create_bind( pirq_dpci->gmsi.gvec = pt_irq_bind->u.msi.gvec; pirq_dpci->gmsi.gflags = gflags; + prev_vcpu_id = pirq_dpci->gmsi.dest_vcpu_id; } } /* Calculate dest_vcpu_id for MSI-type pirq migration. */ @@ -432,7 +433,10 @@ int pt_irq_create_bind( 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; + } } if ( vcpu && iommu_enabled ) hvm_migrate_pirq(pirq_dpci, vcpu); @@ -440,7 +444,8 @@ int pt_irq_create_bind( /* Use interrupt posting if it is supported. */ if ( iommu_intpost ) pi_update_irte(vcpu ? &vcpu->arch.hvm.vmx.pi_desc : NULL, - info, pirq_dpci->gmsi.gvec); + info, pirq_dpci->gmsi.gvec, + prev_vcpu_id >= 0 ? d->vcpu[prev_vcpu_id] : NULL); if ( pt_irq_bind->u.msi.gflags & XEN_DOMCTL_VMSI_X86_UNMASKED ) { @@ -729,7 +734,9 @@ int pt_irq_destroy_bind( what = "bogus"; } else if ( pirq_dpci && pirq_dpci->gmsi.posted ) - pi_update_irte(NULL, pirq, 0); + pi_update_irte(NULL, pirq, 0, + pirq_dpci->gmsi.dest_vcpu_id >= 0 + ? d->vcpu[pirq_dpci->gmsi.dest_vcpu_id] : NULL); if ( pirq_dpci && (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) && list_empty(&pirq_dpci->digl_list) ) diff --git a/xen/drivers/passthrough/vtd/intremap.c b/xen/drivers/passthrough/vtd/intremap.c index c9927e4706..d788a4b9e7 100644 --- a/xen/drivers/passthrough/vtd/intremap.c +++ b/xen/drivers/passthrough/vtd/intremap.c @@ -961,12 +961,13 @@ void iommu_disable_x2apic_IR(void) disable_qinval(drhd->iommu); } +#ifdef CONFIG_HVM /* * This function is used to update the IRTE for posted-interrupt * when guest changes MSI/MSI-X information. */ int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, - const uint8_t gvec) + const uint8_t gvec, struct vcpu *prev) { struct irq_desc *desc; struct msi_desc *msi_desc; @@ -979,8 +980,8 @@ int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, msi_desc = desc->msi_desc; if ( !msi_desc ) { - rc = -ENODEV; - goto unlock_out; + spin_unlock_irq(&desc->lock); + return -ENODEV; } msi_desc->pi_desc = pi_desc; msi_desc->gvec = gvec; @@ -989,10 +990,10 @@ int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, ASSERT(pcidevs_locked()); - return msi_msg_write_remap_rte(msi_desc, &msi_desc->msg); - - unlock_out: - spin_unlock_irq(&desc->lock); + rc = msi_msg_write_remap_rte(msi_desc, &msi_desc->msg); + if ( !rc && prev ) + vlapic_sync_pir_to_irr(prev); return rc; } +#endif diff --git a/xen/include/asm-x86/hvm/vlapic.h b/xen/include/asm-x86/hvm/vlapic.h index dde66b4f0f..b0017d1dae 100644 --- a/xen/include/asm-x86/hvm/vlapic.h +++ b/xen/include/asm-x86/hvm/vlapic.h @@ -150,4 +150,6 @@ bool_t vlapic_match_dest( const struct vlapic *target, const struct vlapic *source, int short_hand, uint32_t dest, bool_t dest_mode); +void vlapic_sync_pir_to_irr(struct vcpu *v); + #endif /* __ASM_X86_HVM_VLAPIC_H__ */ diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h index 8dc392473d..32bfa23648 100644 --- a/xen/include/asm-x86/iommu.h +++ b/xen/include/asm-x86/iommu.h @@ -99,7 +99,7 @@ void iommu_disable_x2apic_IR(void); extern bool untrusted_msi; int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, - const uint8_t gvec); + const uint8_t gvec, struct vcpu *prev); #endif /* !__ARCH_X86_IOMMU_H__ */ /* Thanks, Joe On 10/9/19 5:52 AM, Roger Pau Monne wrote: > When using posted interrupts and the guest migrates MSI from vCPUs Xen > needs to flush any pending PIRR vectors on the previous vCPU, or else > those vectors could get wrongly injected at a later point when the MSI > fields are already updated. > > Rename sync_pir_to_irr to vlapic_sync_pir_to_irr and export it so it > can be called when updating the posted interrupt descriptor field in > pi_update_irte. While there also remove the unlock_out from > pi_update_irte, it's used in a single goto and removing it makes the > function smaller. > > Note that PIRR is synced to IRR both in pt_irq_destroy_bind and > pt_irq_create_bind when the interrupt delivery data is being updated. > > Also store the vCPU ID in multi-destination mode when using posted > interrupts and the interrupt is bound to a single vCPU in order for > posted interrupts to be used. > > While there guard pi_update_irte with CONFIG_HVM since it's only used > with HVM guests. > > Reported-by: Joe Jin <joe.jin@xxxxxxxxxx> > Signed-off-by: Roger Pau Monné <roger.pau@xxxxxxxxxx> > --- > Cc: Joe Jin <joe.jin@xxxxxxxxxx> > Cc: Juergen Gross <jgross@xxxxxxxx> > --- > I would like to see a bug fix for this issue in 4.13. The fix here only > affects posted interrupts, hence I think the risk of breaking anything > else is low. > --- > Changes since v1: > - Store the vcpu id also in multi-dest mode if the interrupt is bound > to a vcpu for posted delivery. > - s/#if/#ifdef/. > --- > xen/arch/x86/hvm/vlapic.c | 6 +++--- > xen/drivers/passthrough/io.c | 13 ++++++++++--- > xen/drivers/passthrough/vtd/intremap.c | 15 ++++++++------- > xen/include/asm-x86/hvm/vlapic.h | 2 ++ > xen/include/asm-x86/iommu.h | 2 +- > 5 files changed, 24 insertions(+), 14 deletions(-) > > diff --git a/xen/arch/x86/hvm/vlapic.c b/xen/arch/x86/hvm/vlapic.c > index 9466258d6f..d255ad8db7 100644 > --- a/xen/arch/x86/hvm/vlapic.c > +++ b/xen/arch/x86/hvm/vlapic.c > @@ -106,7 +106,7 @@ static void vlapic_clear_irr(int vector, struct vlapic > *vlapic) > vlapic_clear_vector(vector, &vlapic->regs->data[APIC_IRR]); > } > > -static void sync_pir_to_irr(struct vcpu *v) > +void vlapic_sync_pir_to_irr(struct vcpu *v) > { > if ( hvm_funcs.sync_pir_to_irr ) > alternative_vcall(hvm_funcs.sync_pir_to_irr, v); > @@ -114,7 +114,7 @@ static void sync_pir_to_irr(struct vcpu *v) > > static int vlapic_find_highest_irr(struct vlapic *vlapic) > { > - sync_pir_to_irr(vlapic_vcpu(vlapic)); > + vlapic_sync_pir_to_irr(vlapic_vcpu(vlapic)); > > return vlapic_find_highest_vector(&vlapic->regs->data[APIC_IRR]); > } > @@ -1493,7 +1493,7 @@ static int lapic_save_regs(struct vcpu *v, > hvm_domain_context_t *h) > if ( !has_vlapic(v->domain) ) > return 0; > > - sync_pir_to_irr(v); > + vlapic_sync_pir_to_irr(v); > > return hvm_save_entry(LAPIC_REGS, v->vcpu_id, h, vcpu_vlapic(v)->regs); > } > diff --git a/xen/drivers/passthrough/io.c b/xen/drivers/passthrough/io.c > index b292e79382..5bf1877726 100644 > --- a/xen/drivers/passthrough/io.c > +++ b/xen/drivers/passthrough/io.c > @@ -341,7 +341,7 @@ int pt_irq_create_bind( > { > uint8_t dest, delivery_mode; > bool dest_mode; > - int dest_vcpu_id; > + int dest_vcpu_id, prev_vcpu_id = -1; > const struct vcpu *vcpu; > uint32_t gflags = pt_irq_bind->u.msi.gflags & > ~XEN_DOMCTL_VMSI_X86_UNMASKED; > @@ -411,6 +411,7 @@ int pt_irq_create_bind( > > pirq_dpci->gmsi.gvec = pt_irq_bind->u.msi.gvec; > pirq_dpci->gmsi.gflags = gflags; > + prev_vcpu_id = pirq_dpci->gmsi.dest_vcpu_id; > } > } > /* Calculate dest_vcpu_id for MSI-type pirq migration. */ > @@ -432,7 +433,10 @@ int pt_irq_create_bind( > 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; > + } > } > if ( vcpu && is_iommu_enabled(d) ) > hvm_migrate_pirq(pirq_dpci, vcpu); > @@ -440,7 +444,8 @@ int pt_irq_create_bind( > /* Use interrupt posting if it is supported. */ > if ( iommu_intpost ) > pi_update_irte(vcpu ? &vcpu->arch.hvm.vmx.pi_desc : NULL, > - info, pirq_dpci->gmsi.gvec); > + info, pirq_dpci->gmsi.gvec, > + prev_vcpu_id >= 0 ? d->vcpu[prev_vcpu_id] : NULL); > > if ( pt_irq_bind->u.msi.gflags & XEN_DOMCTL_VMSI_X86_UNMASKED ) > { > @@ -729,7 +734,9 @@ int pt_irq_destroy_bind( > what = "bogus"; > } > else if ( pirq_dpci && pirq_dpci->gmsi.posted ) > - pi_update_irte(NULL, pirq, 0); > + pi_update_irte(NULL, pirq, 0, > + pirq_dpci->gmsi.dest_vcpu_id >= 0 > + ? d->vcpu[pirq_dpci->gmsi.dest_vcpu_id] : NULL); > > if ( pirq_dpci && (pirq_dpci->flags & HVM_IRQ_DPCI_MAPPED) && > list_empty(&pirq_dpci->digl_list) ) > diff --git a/xen/drivers/passthrough/vtd/intremap.c > b/xen/drivers/passthrough/vtd/intremap.c > index bf846195c4..07c1c1627a 100644 > --- a/xen/drivers/passthrough/vtd/intremap.c > +++ b/xen/drivers/passthrough/vtd/intremap.c > @@ -946,12 +946,13 @@ void intel_iommu_disable_eim(void) > disable_qinval(drhd->iommu); > } > > +#ifdef CONFIG_HVM > /* > * This function is used to update the IRTE for posted-interrupt > * when guest changes MSI/MSI-X information. > */ > int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, > - const uint8_t gvec) > + const uint8_t gvec, struct vcpu *prev) > { > struct irq_desc *desc; > struct msi_desc *msi_desc; > @@ -964,8 +965,8 @@ int pi_update_irte(const struct pi_desc *pi_desc, const > struct pirq *pirq, > msi_desc = desc->msi_desc; > if ( !msi_desc ) > { > - rc = -ENODEV; > - goto unlock_out; > + spin_unlock_irq(&desc->lock); > + return -ENODEV; > } > msi_desc->pi_desc = pi_desc; > msi_desc->gvec = gvec; > @@ -974,10 +975,10 @@ int pi_update_irte(const struct pi_desc *pi_desc, const > struct pirq *pirq, > > ASSERT(pcidevs_locked()); > > - return msi_msg_write_remap_rte(msi_desc, &msi_desc->msg); > - > - unlock_out: > - spin_unlock_irq(&desc->lock); > + rc = msi_msg_write_remap_rte(msi_desc, &msi_desc->msg); > + if ( !rc && prev ) > + vlapic_sync_pir_to_irr(prev); > > return rc; > } > +#endif > diff --git a/xen/include/asm-x86/hvm/vlapic.h > b/xen/include/asm-x86/hvm/vlapic.h > index dde66b4f0f..b0017d1dae 100644 > --- a/xen/include/asm-x86/hvm/vlapic.h > +++ b/xen/include/asm-x86/hvm/vlapic.h > @@ -150,4 +150,6 @@ bool_t vlapic_match_dest( > const struct vlapic *target, const struct vlapic *source, > int short_hand, uint32_t dest, bool_t dest_mode); > > +void vlapic_sync_pir_to_irr(struct vcpu *v); > + > #endif /* __ASM_X86_HVM_VLAPIC_H__ */ > diff --git a/xen/include/asm-x86/iommu.h b/xen/include/asm-x86/iommu.h > index 85741f7c96..314dcfbe47 100644 > --- a/xen/include/asm-x86/iommu.h > +++ b/xen/include/asm-x86/iommu.h > @@ -119,7 +119,7 @@ static inline void iommu_disable_x2apic(void) > extern bool untrusted_msi; > > int pi_update_irte(const struct pi_desc *pi_desc, const struct pirq *pirq, > - const uint8_t gvec); > + const uint8_t gvec, struct vcpu *prev); > > #endif /* !__ARCH_X86_IOMMU_H__ */ > /* > _______________________________________________ Xen-devel mailing list Xen-devel@xxxxxxxxxxxxxxxxxxxx https://lists.xenproject.org/mailman/listinfo/xen-devel
|
Lists.xenproject.org is hosted with RackSpace, monitoring our |