From: Keir Fraser Date: Tue, 30 Oct 2007 10:39:52 +0000 (+0000) Subject: vt-d: Do dpci eoi outside of irq_lock. X-Git-Tag: archive/raspbian/4.8.0-1+rpi1~1^2~14828^2~8 X-Git-Url: https://dgit.raspbian.org/?a=commitdiff_plain;h=06e3f8f27662a8c1af0a4a43558a1dac65c2a97b;p=xen.git vt-d: Do dpci eoi outside of irq_lock. Deadlock may occur if do hvm_dpci_eoi() inside of irq_lock on MP platform. For example, there are two physical cpus. If interrupt is injected on cpu0, but vcpu is migrated to cpu1 and it does eoi inside of irq_lock, then IPI will be issued to cpu0. At the same time, cpu0 may have disabled irq and is acquiring the same irq_lock. In addition, current code cannot guarantee do hvm_dpci_eoi() inside of irq_lock when timeout. This patch does hvm_dpci_eoi() outside of irq_lock, and solves above problems. Signed-off-by: Xiaohui Xin Signed-off-by: Weidong Han Signed-off-by: Keir Fraser --- diff --git a/xen/arch/x86/hvm/irq.c b/xen/arch/x86/hvm/irq.c index 9d1d2d7e49..b789fbfc34 100644 --- a/xen/arch/x86/hvm/irq.c +++ b/xen/arch/x86/hvm/irq.c @@ -26,7 +26,7 @@ #include #include -void __hvm_pci_intx_assert( +static void __hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; @@ -59,7 +59,7 @@ void hvm_pci_intx_assert( spin_unlock(&d->arch.hvm_domain.irq_lock); } -void __hvm_pci_intx_deassert( +static void __hvm_pci_intx_deassert( struct domain *d, unsigned int device, unsigned int intx) { struct hvm_irq *hvm_irq = &d->arch.hvm_domain.irq; diff --git a/xen/arch/x86/hvm/vioapic.c b/xen/arch/x86/hvm/vioapic.c index 31db4454ab..670cdf5979 100644 --- a/xen/arch/x86/hvm/vioapic.c +++ b/xen/arch/x86/hvm/vioapic.c @@ -459,7 +459,11 @@ void vioapic_update_EOI(struct domain *d, int vector) ent->fields.remote_irr = 0; if ( vtd_enabled ) + { + spin_unlock(&d->arch.hvm_domain.irq_lock); hvm_dpci_eoi(current->domain, gsi, ent); + spin_lock(&d->arch.hvm_domain.irq_lock); + } if ( (ent->fields.trig_mode == VIOAPIC_LEVEL_TRIG) && !ent->fields.mask && diff --git a/xen/arch/x86/hvm/vmx/vtd/io.c b/xen/arch/x86/hvm/vmx/vtd/io.c index a724bb7986..28d42a973a 100644 --- a/xen/arch/x86/hvm/vmx/vtd/io.c +++ b/xen/arch/x86/hvm/vmx/vtd/io.c @@ -145,8 +145,6 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci; uint32_t device, intx, machine_gsi; - ASSERT(spin_is_locked(&d->arch.hvm_domain.irq_lock)); - if ( !vtd_enabled || (hvm_irq_dpci == NULL) || !hvm_irq_dpci->girq[guest_gsi].valid ) return; @@ -157,7 +155,7 @@ void hvm_dpci_eoi(struct domain *d, unsigned int guest_gsi, intx = hvm_irq_dpci->girq[guest_gsi].intx; gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: device %x intx %x\n", device, intx); - __hvm_pci_intx_deassert(d, device, intx); + hvm_pci_intx_deassert(d, device, intx); if ( (ent == NULL) || !ent->fields.mask ) pirq_guest_eoi(d, machine_gsi); } diff --git a/xen/arch/x86/hvm/vpic.c b/xen/arch/x86/hvm/vpic.c index 161129a97f..4a3fc5ae5a 100644 --- a/xen/arch/x86/hvm/vpic.c +++ b/xen/arch/x86/hvm/vpic.c @@ -249,13 +249,13 @@ static void vpic_ioport_write( vpic->isr &= ~(1 << irq); if ( cmd == 7 ) vpic->priority_add = (irq + 1) & 7; - if ( vtd_enabled ) - { - irq |= ((addr & 0xa0) == 0xa0) ? 8 : 0; - hvm_dpci_eoi(current->domain, - hvm_isa_irq_to_gsi(irq), NULL); - } - break; + /* Release lock and EOI the physical interrupt (if any). */ + vpic_update_int_output(vpic); + vpic_unlock(vpic); + hvm_dpci_eoi(current->domain, + hvm_isa_irq_to_gsi((addr >> 7) ? (irq|8) : irq), + NULL); + return; /* bail immediately */ case 6: /* Set Priority */ vpic->priority_add = (val + 1) & 7; break; diff --git a/xen/include/asm-x86/hvm/irq.h b/xen/include/asm-x86/hvm/irq.h index b5107c8e68..289a209d44 100644 --- a/xen/include/asm-x86/hvm/irq.h +++ b/xen/include/asm-x86/hvm/irq.h @@ -121,12 +121,8 @@ struct hvm_irq { #define hvm_isa_irq_to_gsi(isa_irq) ((isa_irq) ? : 2) /* Modify state of a PCI INTx wire. */ -void __hvm_pci_intx_assert( - struct domain *d, unsigned int device, unsigned int intx); void hvm_pci_intx_assert( struct domain *d, unsigned int device, unsigned int intx); -void __hvm_pci_intx_deassert( - struct domain *d, unsigned int device, unsigned int intx); void hvm_pci_intx_deassert( struct domain *d, unsigned int device, unsigned int intx);