vt-d: Do dpci eoi outside of irq_lock.
authorKeir Fraser <keir@xensource.com>
Tue, 30 Oct 2007 10:39:52 +0000 (10:39 +0000)
committerKeir Fraser <keir@xensource.com>
Tue, 30 Oct 2007 10:39:52 +0000 (10:39 +0000)
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 <xiaohui.xin@intel.com>
Signed-off-by: Weidong Han <weidong.han@intel.com>
Signed-off-by: Keir Fraser <keir@xensource.com>
xen/arch/x86/hvm/irq.c
xen/arch/x86/hvm/vioapic.c
xen/arch/x86/hvm/vmx/vtd/io.c
xen/arch/x86/hvm/vpic.c
xen/include/asm-x86/hvm/irq.h

index 9d1d2d7e492f8678d6d410dc2ff453f53bc98692..b789fbfc343e5335a065e2884b473e07306572ee 100644 (file)
@@ -26,7 +26,7 @@
 #include <asm/hvm/domain.h>
 #include <asm/hvm/support.h>
 
-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;
index 31db4454abb0e7e3ab125f0582636da24a61c766..670cdf5979ee33bab4c108833ff30220c3d54ef5 100644 (file)
@@ -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 &&
index a724bb7986869aadbb552fa62d2e92768ddaab7d..28d42a973a08066120acd45d439e8c4eb22484f9 100644 (file)
@@ -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);
 }
index 161129a97f2ad8e82e5b44541caef0edb55a3efa..4a3fc5ae5a68585dea93cb4d17c4f5d5977284b3 100644 (file)
@@ -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;
index b5107c8e6834ca1465f7e42f87864e7905c934d6..289a209d449a8b2ce06f725e6b4dbc9a2ceaef48 100644 (file)
@@ -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);