[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-changelog] [xen-unstable] vt-d: Support intra-domain shared interrupt.



# HG changeset patch
# User Keir Fraser <keir@xxxxxxxxxxxxx>
# Date 1194448806 0
# Node ID 4fd6610949f1e3ee3286dead75411bfb1a916d8e
# Parent  644e7577f6ee00f746a63a63ca16284cc31f9ee8
vt-d: Support intra-domain shared interrupt.

Inter-domain shared interrupt has been supported by timeout method,
but it still doesn't support intra-domain shared interrupt, that is
assigning multiple devices which share a physical irq to the same
domain. This patch implements intra-domain shared interrupt
support. In addition, this patch maps link to guest device/intx
instead of directly mapping isairq in pt_irq_create_bind_vtd(),
because at this point the isairqs got from pci_link are always 0.

Note that assigning multiple devices to guests which uses PIC to
handle interrupts may be failed, because different links possibly
connect to same irq.

Signed-off-by: Weidong Han <weidong.han@xxxxxxxxx>
---
 xen/arch/x86/hvm/irq.c        |   13 +---
 xen/arch/x86/hvm/vmx/intr.c   |   17 ++++-
 xen/arch/x86/hvm/vmx/vtd/io.c |  121 ++++++++++++++++++++++++++++--------------
 xen/include/asm-x86/hvm/irq.h |   29 +++++++---
 4 files changed, 119 insertions(+), 61 deletions(-)

diff -r 644e7577f6ee -r 4fd6610949f1 xen/arch/x86/hvm/irq.c
--- a/xen/arch/x86/hvm/irq.c    Wed Nov 07 14:53:32 2007 +0000
+++ b/xen/arch/x86/hvm/irq.c    Wed Nov 07 15:20:06 2007 +0000
@@ -192,15 +192,12 @@ void hvm_set_pci_link_route(struct domai
     hvm_irq->pci_link.route[link] = isa_irq;
 
     /* PCI pass-through fixup. */
-    if ( hvm_irq->dpci && hvm_irq->dpci->girq[old_isa_irq].valid )
-    {
-        uint32_t device = hvm_irq->dpci->girq[old_isa_irq].device;
-        uint32_t intx = hvm_irq->dpci->girq[old_isa_irq].intx;
-        if ( link == hvm_pci_intx_link(device, intx) )
-        {
-            hvm_irq->dpci->girq[isa_irq] = hvm_irq->dpci->girq[old_isa_irq];
+    if ( hvm_irq->dpci && hvm_irq->dpci->link[link].valid )
+    {
+        hvm_irq->dpci->girq[isa_irq] = hvm_irq->dpci->link[link];
+        if ( hvm_irq->dpci->girq[old_isa_irq].device ==
+             hvm_irq->dpci->link[link].device )
             hvm_irq->dpci->girq[old_isa_irq].valid = 0;
-        }
     }
 
     if ( hvm_irq->pci_link_assert_count[link] == 0 )
diff -r 644e7577f6ee -r 4fd6610949f1 xen/arch/x86/hvm/vmx/intr.c
--- a/xen/arch/x86/hvm/vmx/intr.c       Wed Nov 07 14:53:32 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/intr.c       Wed Nov 07 15:20:06 2007 +0000
@@ -113,6 +113,7 @@ static void vmx_dirq_assist(struct vcpu 
     uint32_t device, intx;
     struct domain *d = v->domain;
     struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
+    struct dev_intx_gsi *dig;
 
     if ( !vtd_enabled || (v->vcpu_id != 0) || (hvm_irq_dpci == NULL) )
         return;
@@ -122,11 +123,17 @@ static void vmx_dirq_assist(struct vcpu 
           irq = find_next_bit(hvm_irq_dpci->dirq_mask, NR_IRQS, irq + 1) )
     {
         stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(irq)]);
-
-        test_and_clear_bit(irq, &hvm_irq_dpci->dirq_mask);
-        device = hvm_irq_dpci->mirq[irq].device;
-        intx = hvm_irq_dpci->mirq[irq].intx;
-        hvm_pci_intx_assert(d, device, intx);
+        clear_bit(irq, &hvm_irq_dpci->dirq_mask);
+
+        list_for_each_entry ( dig, &hvm_irq_dpci->mirq[irq].dig_list, list )
+        {
+            device = dig->device;
+            intx = dig->intx;
+            hvm_pci_intx_assert(d, device, intx);
+            spin_lock(&hvm_irq_dpci->dirq_lock);
+            hvm_irq_dpci->mirq[irq].pending++;
+            spin_unlock(&hvm_irq_dpci->dirq_lock);
+        }
 
         /*
          * Set a timer to see if the guest can finish the interrupt or not. For
diff -r 644e7577f6ee -r 4fd6610949f1 xen/arch/x86/hvm/vmx/vtd/io.c
--- a/xen/arch/x86/hvm/vmx/vtd/io.c     Wed Nov 07 14:53:32 2007 +0000
+++ b/xen/arch/x86/hvm/vmx/vtd/io.c     Wed Nov 07 15:20:06 2007 +0000
@@ -47,14 +47,27 @@
 
 static void pt_irq_time_out(void *data)
 {
-    struct hvm_irq_dpci_mapping *irq_map = data;
-    unsigned int guest_gsi, machine_gsi;
-    struct domain *d = irq_map->dom;
-
-    guest_gsi = irq_map->guest_gsi;
-    machine_gsi = d->arch.hvm_domain.irq.dpci->girq[guest_gsi].machine_gsi;
-    clear_bit(machine_gsi, d->arch.hvm_domain.irq.dpci->dirq_mask);
-    hvm_dpci_eoi(irq_map->dom, guest_gsi, NULL);
+    struct hvm_mirq_dpci_mapping *irq_map = data;
+    unsigned int guest_gsi, machine_gsi = 0;
+    struct hvm_irq_dpci *dpci = irq_map->dom->arch.hvm_domain.irq.dpci;
+    struct dev_intx_gsi *dig;
+    uint32_t device, intx;
+
+    list_for_each_entry ( dig, &irq_map->dig_list, list )
+    {
+        guest_gsi = dig->gsi;
+        machine_gsi = dpci->girq[guest_gsi].machine_gsi;
+        device = dig->device;
+        intx = dig->intx;
+        hvm_pci_intx_deassert(irq_map->dom, device, intx);
+    }
+
+    clear_bit(machine_gsi, dpci->dirq_mask);
+    stop_timer(&dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+    spin_lock(&dpci->dirq_lock);
+    dpci->mirq[machine_gsi].pending = 0;
+    spin_unlock(&dpci->dirq_lock);
+    pirq_guest_eoi(irq_map->dom, machine_gsi);
 }
 
 int pt_irq_create_bind_vtd(
@@ -62,8 +75,8 @@ int pt_irq_create_bind_vtd(
 {
     struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
     uint32_t machine_gsi, guest_gsi;
-    uint32_t device, intx;
-    uint32_t link, isa_irq;
+    uint32_t device, intx, link;
+    struct dev_intx_gsi *dig;
 
     if ( hvm_irq_dpci == NULL )
     {
@@ -72,6 +85,9 @@ int pt_irq_create_bind_vtd(
             return -ENOMEM;
 
         memset(hvm_irq_dpci, 0, sizeof(*hvm_irq_dpci));
+        spin_lock_init(&hvm_irq_dpci->dirq_lock);
+        for ( int i = 0; i < NR_IRQS; i++ )
+            INIT_LIST_HEAD(&hvm_irq_dpci->mirq[i].dig_list);
 
         if ( cmpxchg((unsigned long *)&d->arch.hvm_domain.irq.dpci,
                      0, (unsigned long)hvm_irq_dpci) != 0 )
@@ -85,35 +101,42 @@ int pt_irq_create_bind_vtd(
     intx = pt_irq_bind->u.pci.intx;
     guest_gsi = hvm_pci_intx_gsi(device, intx);
     link = hvm_pci_intx_link(device, intx);
-    isa_irq = d->arch.hvm_domain.irq.pci_link.route[link];
-
-    hvm_irq_dpci->mirq[machine_gsi].valid = 1;
-    hvm_irq_dpci->mirq[machine_gsi].device = device;
-    hvm_irq_dpci->mirq[machine_gsi].intx = intx;
-    hvm_irq_dpci->mirq[machine_gsi].guest_gsi = guest_gsi;
-    hvm_irq_dpci->mirq[machine_gsi].dom = d;
-
+
+    dig = xmalloc(struct dev_intx_gsi);
+    if ( !dig )
+        return -ENOMEM;
+
+    dig->device = device;
+    dig->intx = intx;
+    dig->gsi = guest_gsi;
+    list_add_tail(&dig->list,
+                  &hvm_irq_dpci->mirq[machine_gsi].dig_list);
+ 
     hvm_irq_dpci->girq[guest_gsi].valid = 1;
     hvm_irq_dpci->girq[guest_gsi].device = device;
     hvm_irq_dpci->girq[guest_gsi].intx = intx;
     hvm_irq_dpci->girq[guest_gsi].machine_gsi = machine_gsi;
-    hvm_irq_dpci->girq[guest_gsi].dom = d;
-
-    hvm_irq_dpci->girq[isa_irq].valid = 1;
-    hvm_irq_dpci->girq[isa_irq].device = device;
-    hvm_irq_dpci->girq[isa_irq].intx = intx;
-    hvm_irq_dpci->girq[isa_irq].machine_gsi = machine_gsi;
-    hvm_irq_dpci->girq[isa_irq].dom = d;
-
-    init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
-               pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
-
-    /* Deal with GSI for legacy devices. */
-    pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
-    gdprintk(XENLOG_ERR,
-             "XEN_DOMCTL_irq_mapping: m_irq = %x device = %x intx = %x\n",
+
+    hvm_irq_dpci->link[link].valid = 1;
+    hvm_irq_dpci->link[link].device = device;
+    hvm_irq_dpci->link[link].intx = intx;
+    hvm_irq_dpci->link[link].machine_gsi = machine_gsi;
+
+    /* Bind the same mirq once in the same domain */
+    if ( !hvm_irq_dpci->mirq[machine_gsi].valid )
+    {
+        hvm_irq_dpci->mirq[machine_gsi].valid = 1;
+        hvm_irq_dpci->mirq[machine_gsi].dom = d;
+
+        init_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)],
+                   pt_irq_time_out, &hvm_irq_dpci->mirq[machine_gsi], 0);
+        /* Deal with gsi for legacy devices */
+        pirq_guest_bind(d->vcpu[0], machine_gsi, BIND_PIRQ__WILL_SHARE);
+    }
+
+    gdprintk(XENLOG_INFO,
+             "VT-d irq bind: m_irq = %x device = %x intx = %x\n",
              machine_gsi, device, intx);
-
     return 0;
 }
 
@@ -150,14 +173,22 @@ void hvm_dpci_eoi(struct domain *d, unsi
         return;
 
     machine_gsi = hvm_irq_dpci->girq[guest_gsi].machine_gsi;
-    stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
     device = hvm_irq_dpci->girq[guest_gsi].device;
     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);
-    if ( (ent == NULL) || !ent->fields.mask )
-        pirq_guest_eoi(d, machine_gsi);
+ 
+    spin_lock(&hvm_irq_dpci->dirq_lock);
+    if ( --hvm_irq_dpci->mirq[machine_gsi].pending == 0 )
+    {
+        spin_unlock(&hvm_irq_dpci->dirq_lock);
+
+        gdprintk(XENLOG_INFO, "hvm_dpci_eoi:: mirq = %x\n", machine_gsi);
+        stop_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(machine_gsi)]);
+        if ( (ent == NULL) || !ent->fields.mask )
+            pirq_guest_eoi(d, machine_gsi);
+    }
+    else
+        spin_unlock(&hvm_irq_dpci->dirq_lock);
 }
 
 void iommu_domain_destroy(struct domain *d)
@@ -165,8 +196,9 @@ void iommu_domain_destroy(struct domain 
     struct hvm_irq_dpci *hvm_irq_dpci = d->arch.hvm_domain.irq.dpci;
     uint32_t i;
     struct hvm_iommu *hd  = domain_hvm_iommu(d);
-    struct list_head *ioport_list, *tmp;
+    struct list_head *ioport_list, *dig_list, *tmp;
     struct g2m_ioport *ioport;
+    struct dev_intx_gsi *dig;
 
     if ( !vtd_enabled )
         return;
@@ -178,7 +210,16 @@ void iommu_domain_destroy(struct domain 
             {
                 pirq_guest_unbind(d, i);
                 kill_timer(&hvm_irq_dpci->hvm_timer[irq_to_vector(i)]);
+
+                list_for_each_safe ( dig_list, tmp,
+                                     &hvm_irq_dpci->mirq[i].dig_list )
+                {
+                    dig = list_entry(dig_list, struct dev_intx_gsi, list);
+                    list_del(&dig->list);
+                    xfree(dig);
+                }
             }
+
         d->arch.hvm_domain.irq.dpci = NULL;
         xfree(hvm_irq_dpci);
     }
diff -r 644e7577f6ee -r 4fd6610949f1 xen/include/asm-x86/hvm/irq.h
--- a/xen/include/asm-x86/hvm/irq.h     Wed Nov 07 14:53:32 2007 +0000
+++ b/xen/include/asm-x86/hvm/irq.h     Wed Nov 07 15:20:06 2007 +0000
@@ -30,22 +30,35 @@
 #include <asm/hvm/vioapic.h>
 #include <public/hvm/save.h>
 
-struct hvm_irq_dpci_mapping {
+struct dev_intx_gsi {
+    struct list_head list;
+    uint8_t device;
+    uint8_t intx;
+    uint8_t gsi;
+};
+
+struct hvm_mirq_dpci_mapping {
+    uint8_t valid;
+    int pending;
+    struct list_head dig_list;
+    struct domain *dom;
+};
+
+struct hvm_girq_dpci_mapping {
     uint8_t valid;
     uint8_t device;
     uint8_t intx;
-    struct domain *dom;
-    union {
-        uint8_t guest_gsi;
-        uint8_t machine_gsi;
-    };
+    uint8_t machine_gsi;
 };
 
 struct hvm_irq_dpci {
+    spinlock_t dirq_lock;
     /* Machine IRQ to guest device/intx mapping. */
-    struct hvm_irq_dpci_mapping mirq[NR_IRQS];
+    struct hvm_mirq_dpci_mapping mirq[NR_IRQS];
     /* Guest IRQ to guest device/intx mapping. */
-    struct hvm_irq_dpci_mapping girq[NR_IRQS];
+    struct hvm_girq_dpci_mapping girq[NR_IRQS];
+    /* Link to guest device/intx mapping. */
+    struct hvm_girq_dpci_mapping link[4];
     DECLARE_BITMAP(dirq_mask, NR_IRQS);
     struct timer hvm_timer[NR_IRQS];
 };

_______________________________________________
Xen-changelog mailing list
Xen-changelog@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-changelog


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.