[PATCH 11/19] pci-assign: Rework MSI-X route setup

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

 



Use kvm_irqchip_add_msi_route and introduce kvm_irqchip_update_msi_route
to set up the required IRQ routes for MSI-X injections. This removes the
last direct interaction with the IRQ routing API of the KVM kernel so
that we can remove/unexport related services.

Signed-off-by: Jan Kiszka <jan.kiszka@xxxxxxxxxxx>
---
 hw/device-assignment.c |   71 ++++++++++-----------------
 kvm-all.c              |   51 ++++++++++++++++---
 kvm-stub.c             |    9 ---
 kvm.h                  |    5 +--
 qemu-kvm.c             |  128 ------------------------------------------------
 qemu-kvm.h             |   22 --------
 6 files changed, 71 insertions(+), 215 deletions(-)

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index af8a5aa..7ffd26c 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -141,8 +141,6 @@ typedef struct AssignedDevice {
     uint8_t emulate_config_write[PCI_CONFIG_SPACE_SIZE];
     int msi_virq_nr;
     int *msi_virq;
-    int irq_entries_nr;
-    struct kvm_irq_routing_entry *entry;
     MSIXTableEntry *msix_table;
     target_phys_addr_t msix_table_addr;
     uint16_t msix_max;
@@ -701,7 +699,7 @@ again:
 
 static QLIST_HEAD(, AssignedDevice) devs = QLIST_HEAD_INITIALIZER(devs);
 
-static void free_dev_irq_entries(AssignedDevice *dev)
+static void free_msi_virqs(AssignedDevice *dev)
 {
     int i;
 
@@ -714,15 +712,6 @@ static void free_dev_irq_entries(AssignedDevice *dev)
     g_free(dev->msi_virq);
     dev->msi_virq = NULL;
     dev->msi_virq_nr = 0;
-
-    for (i = 0; i < dev->irq_entries_nr; i++) {
-        if (dev->entry[i].type) {
-            kvm_del_routing_entry(&dev->entry[i]);
-        }
-    }
-    g_free(dev->entry);
-    dev->entry = NULL;
-    dev->irq_entries_nr = 0;
 }
 
 static void free_assigned_device(AssignedDevice *dev)
@@ -778,7 +767,7 @@ static void free_assigned_device(AssignedDevice *dev)
         close(dev->real_device.config_fd);
     }
 
-    free_dev_irq_entries(dev);
+    free_msi_virqs(dev);
 }
 
 static void assign_failed_examine(AssignedDevice *dev)
@@ -1001,7 +990,7 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev)
         if (r && r != -ENXIO)
             perror("assigned_dev_update_msi: deassign irq");
 
-        free_dev_irq_entries(assigned_dev);
+        free_msi_virqs(assigned_dev);
 
         assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
         pci_device_set_intx_routing_notifier(pci_dev, NULL);
@@ -1046,6 +1035,7 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
     uint16_t entries_nr = 0;
     int i, r = 0;
     MSIXTableEntry *entry = adev->msix_table;
+    MSIMessage msg;
 
     /* Get the usable entry number for allocating */
     for (i = 0; i < adev->msix_max; i++, entry++) {
@@ -1069,45 +1059,38 @@ static int assigned_dev_update_msix_mmio(PCIDevice *pci_dev)
         return r;
     }
 
-    free_dev_irq_entries(adev);
+    free_msi_virqs(adev);
 
-    adev->irq_entries_nr = adev->msix_max;
-    adev->entry = g_malloc0(adev->msix_max * sizeof(*(adev->entry)));
+    adev->msi_virq_nr = adev->msix_max;
+    adev->msi_virq = g_malloc(adev->msix_max * sizeof(*adev->msi_virq));
 
     entry = adev->msix_table;
     for (i = 0; i < adev->msix_max; i++, entry++) {
+        adev->msi_virq[i] = -1;
+
         if (msix_masked(entry)) {
             continue;
         }
 
-        r = kvm_get_irq_route_gsi();
-        if (r < 0)
+        msg.address = entry->addr_lo | ((uint64_t)entry->addr_hi << 32);
+        msg.data = entry->data;
+        r = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (r < 0) {
             return r;
-
-        adev->entry[i].gsi = r;
-        adev->entry[i].type = KVM_IRQ_ROUTING_MSI;
-        adev->entry[i].flags = 0;
-        adev->entry[i].u.msi.address_lo = entry->addr_lo;
-        adev->entry[i].u.msi.address_hi = entry->addr_hi;
-        adev->entry[i].u.msi.data = entry->data;
+        }
+        adev->msi_virq[i] = r;
 
         DEBUG("MSI-X vector %d, gsi %d, addr %08x_%08x, data %08x\n", i,
               r, entry->addr_hi, entry->addr_lo, entry->data);
 
-        kvm_add_routing_entry(kvm_state, &adev->entry[i]);
-
         r = kvm_device_msix_set_vector(kvm_state, adev->dev_id, i,
-                                       adev->entry[i].gsi);
+                                       adev->msi_virq[i]);
         if (r) {
             fprintf(stderr, "fail to set MSI-X entry! %s\n", strerror(-r));
             break;
         }
     }
 
-    if (r == 0) {
-        kvm_irqchip_commit_routes(kvm_state);
-    }
-
     return r;
 }
 
@@ -1127,13 +1110,13 @@ static void assigned_dev_update_msix(PCIDevice *pci_dev)
      * MSIX or intends to start. */
     if ((assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSIX) ||
         (ctrl_word & PCI_MSIX_FLAGS_ENABLE)) {
-
-        free_dev_irq_entries(assigned_dev);
         r = kvm_device_msix_deassign(kvm_state, assigned_dev->dev_id);
         /* -ENXIO means no assigned irq */
         if (r && r != -ENXIO)
             perror("assigned_dev_update_msix: deassign irq");
 
+        free_msi_virqs(assigned_dev);
+
         assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
         pci_device_set_intx_routing_notifier(pci_dev, NULL);
     }
@@ -1147,7 +1130,7 @@ static void assigned_dev_update_msix(PCIDevice *pci_dev)
             return;
         }
 
-        if (assigned_dev->irq_entries_nr) {
+        if (assigned_dev->msi_virq_nr > 0) {
             if (kvm_assign_irq(kvm_state, &assigned_irq_data) < 0) {
                 perror("assigned_dev_enable_msix: assign irq");
                 return;
@@ -1561,27 +1544,25 @@ static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
              */
         } else if (msix_masked(&orig) && !msix_masked(entry)) {
             /* Vector unmasked */
-            if (i >= adev->irq_entries_nr || !adev->entry[i].type) {
+            if (i >= adev->msi_virq_nr || adev->msi_virq[i] < 0) {
                 /* Previously unassigned vector, start from scratch */
                 assigned_dev_update_msix(pdev);
                 return;
             } else {
                 /* Update an existing, previously masked vector */
-                struct kvm_irq_routing_entry orig = adev->entry[i];
+                MSIMessage msg;
                 int ret;
 
-                adev->entry[i].u.msi.address_lo = entry->addr_lo;
-                adev->entry[i].u.msi.address_hi = entry->addr_hi;
-                adev->entry[i].u.msi.data = entry->data;
+                msg.address = entry->addr_lo |
+                    ((uint64_t)entry->addr_hi << 32);
+                msg.data = entry->data;
 
-                ret = kvm_update_routing_entry(&orig, &adev->entry[i]);
+                ret = kvm_irqchip_update_msi_route(kvm_state,
+                                                   adev->msi_virq[i], msg);
                 if (ret) {
                     fprintf(stderr,
                             "Error updating irq routing entry (%d)\n", ret);
-                    return;
                 }
-
-                kvm_irqchip_commit_routes(kvm_state);
             }
         }
     }
diff --git a/kvm-all.c b/kvm-all.c
index 979c8d7..8ab47f1 100644
--- a/kvm-all.c
+++ b/kvm-all.c
@@ -922,7 +922,7 @@ static void kvm_init_irq_routing(KVMState *s)
     kvm_arch_init_irq_routing(s);
 }
 
-void kvm_irqchip_commit_routes(KVMState *s)
+static void kvm_irqchip_commit_routes(KVMState *s)
 {
     int ret;
 
@@ -931,7 +931,7 @@ void kvm_irqchip_commit_routes(KVMState *s)
     assert(ret == 0);
 }
 
-void kvm_add_routing_entry(KVMState *s,
+static void kvm_add_routing_entry(KVMState *s,
                                   struct kvm_irq_routing_entry *entry)
 {
     struct kvm_irq_routing_entry *new;
@@ -960,6 +960,30 @@ void kvm_add_routing_entry(KVMState *s,
     kvm_irqchip_commit_routes(s);
 }
 
+static int kvm_update_routing_entry(KVMState *s,
+                                    struct kvm_irq_routing_entry *new_entry)
+{
+    struct kvm_irq_routing_entry *entry;
+    int n;
+
+    for (n = 0; n < s->irq_routes->nr; n++) {
+        entry = &s->irq_routes->entries[n];
+        if (entry->gsi != new_entry->gsi) {
+            continue;
+        }
+
+        entry->type = new_entry->type;
+        entry->flags = new_entry->flags;
+        entry->u = new_entry->u;
+
+        kvm_irqchip_commit_routes(s);
+
+        return 0;
+    }
+
+    return -ESRCH;
+}
+
 void kvm_irqchip_add_irq_route(KVMState *s, int irq, int irqchip, int pin)
 {
     struct kvm_irq_routing_entry e;
@@ -1122,6 +1146,24 @@ int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg)
     return virq;
 }
 
+int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg)
+{
+    struct kvm_irq_routing_entry kroute;
+
+    if (!kvm_irqchip_in_kernel()) {
+        return -ENOSYS;
+    }
+
+    kroute.gsi = virq;
+    kroute.type = KVM_IRQ_ROUTING_MSI;
+    kroute.flags = 0;
+    kroute.u.msi.address_lo = (uint32_t)msg.address;
+    kroute.u.msi.address_hi = msg.address >> 32;
+    kroute.u.msi.data = msg.data;
+
+    return kvm_update_routing_entry(s, &kroute);
+}
+
 static int kvm_irqchip_assign_irqfd(KVMState *s, int fd, int virq, bool assign)
 {
     struct kvm_irqfd irqfd = {
@@ -1143,11 +1185,6 @@ static void kvm_init_irq_routing(KVMState *s)
 {
 }
 
-int kvm_irqchip_commit_routes(KVMState *s)
-{
-    return -ENOSYS;
-}
-
 void kvm_irqchip_release_virq(KVMState *s, int virq)
 {
 }
diff --git a/kvm-stub.c b/kvm-stub.c
index 6c8d980..94c9ea1 100644
--- a/kvm-stub.c
+++ b/kvm-stub.c
@@ -122,15 +122,6 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign, uint
     return -ENOSYS;
 }
 
-int kvm_get_irq_route_gsi(void)
-{
-    return -ENOSYS;
-}
-
-void kvm_irqchip_commit_routes(KVMState *s)
-{
-}
-
 int kvm_on_sigbus_vcpu(CPUArchState *env, int code, void *addr)
 {
     return 1;
diff --git a/kvm.h b/kvm.h
index cdfbb82..0c09be8 100644
--- a/kvm.h
+++ b/kvm.h
@@ -273,6 +273,7 @@ int kvm_set_ioeventfd_mmio(int fd, uint32_t adr, uint32_t val, bool assign,
 int kvm_set_ioeventfd_pio_word(int fd, uint16_t adr, uint16_t val, bool assign);
 
 int kvm_irqchip_add_msi_route(KVMState *s, MSIMessage msg);
+int kvm_irqchip_update_msi_route(KVMState *s, int virq, MSIMessage msg);
 void kvm_irqchip_release_virq(KVMState *s, int virq);
 
 int kvm_irqchip_add_irqfd(KVMState *s, int fd, int virq);
@@ -280,10 +281,6 @@ int kvm_irqchip_remove_irqfd(KVMState *s, int fd, int virq);
 int kvm_irqchip_add_irq_notifier(KVMState *s, EventNotifier *n, int virq);
 int kvm_irqchip_remove_irq_notifier(KVMState *s, EventNotifier *n, int virq);
 
-int kvm_get_irq_route_gsi(void);
-
-void kvm_irqchip_commit_routes(KVMState *s);
-
 #ifdef NEED_CPU_H
 #include "qemu-kvm.h"
 #endif
diff --git a/qemu-kvm.c b/qemu-kvm.c
index ec1911f..e45e4a7 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -57,134 +57,6 @@ int kvm_assign_irq(KVMState *s, struct kvm_assigned_irq *assigned_irq)
 #endif
 #endif
 
-int kvm_del_routing_entry(struct kvm_irq_routing_entry *entry)
-{
-#ifdef KVM_CAP_IRQ_ROUTING
-    KVMState *s = kvm_state;
-    struct kvm_irq_routing_entry *e, *p;
-    int i, gsi, found = 0;
-
-    gsi = entry->gsi;
-
-    for (i = 0; i < s->irq_routes->nr; ++i) {
-        e = &s->irq_routes->entries[i];
-        if (e->type == entry->type && e->gsi == gsi) {
-            switch (e->type) {
-            case KVM_IRQ_ROUTING_IRQCHIP:{
-                    if (e->u.irqchip.irqchip ==
-                        entry->u.irqchip.irqchip
-                        && e->u.irqchip.pin == entry->u.irqchip.pin) {
-                        p = &s->irq_routes->entries[--s->irq_routes->nr];
-                        *e = *p;
-                        found = 1;
-                    }
-                    break;
-                }
-            case KVM_IRQ_ROUTING_MSI:{
-                    if (e->u.msi.address_lo ==
-                        entry->u.msi.address_lo
-                        && e->u.msi.address_hi ==
-                        entry->u.msi.address_hi
-                        && e->u.msi.data == entry->u.msi.data) {
-                        p = &s->irq_routes->entries[--s->irq_routes->nr];
-                        *e = *p;
-                        found = 1;
-                    }
-                    break;
-                }
-            default:
-                break;
-            }
-            if (found) {
-                /* If there are no other users of this GSI
-                 * mark it available in the bitmap */
-                for (i = 0; i < s->irq_routes->nr; i++) {
-                    e = &s->irq_routes->entries[i];
-                    if (e->gsi == gsi)
-                        break;
-                }
-                if (i == s->irq_routes->nr) {
-                    clear_gsi(s, gsi);
-                }
-
-                return 0;
-            }
-        }
-    }
-    return -ESRCH;
-#else
-    return -ENOSYS;
-#endif
-}
-
-int kvm_update_routing_entry(struct kvm_irq_routing_entry *entry,
-                             struct kvm_irq_routing_entry *newentry)
-{
-#ifdef KVM_CAP_IRQ_ROUTING
-    KVMState *s = kvm_state;
-    struct kvm_irq_routing_entry *e;
-    int i;
-
-    if (entry->gsi != newentry->gsi || entry->type != newentry->type) {
-        return -EINVAL;
-    }
-
-    for (i = 0; i < s->irq_routes->nr; ++i) {
-        e = &s->irq_routes->entries[i];
-        if (e->type != entry->type || e->gsi != entry->gsi) {
-            continue;
-        }
-        switch (e->type) {
-        case KVM_IRQ_ROUTING_IRQCHIP:
-            if (e->u.irqchip.irqchip == entry->u.irqchip.irqchip &&
-                e->u.irqchip.pin == entry->u.irqchip.pin) {
-                memcpy(&e->u.irqchip, &newentry->u.irqchip,
-                       sizeof e->u.irqchip);
-                return 0;
-            }
-            break;
-        case KVM_IRQ_ROUTING_MSI:
-            if (e->u.msi.address_lo == entry->u.msi.address_lo &&
-                e->u.msi.address_hi == entry->u.msi.address_hi &&
-                e->u.msi.data == entry->u.msi.data) {
-                memcpy(&e->u.msi, &newentry->u.msi, sizeof e->u.msi);
-                return 0;
-            }
-            break;
-        default:
-            break;
-        }
-    }
-    return -ESRCH;
-#else
-    return -ENOSYS;
-#endif
-}
-
-int kvm_get_irq_route_gsi(void)
-{
-#ifdef KVM_CAP_IRQ_ROUTING
-    KVMState *s = kvm_state;
-    int max_words = ALIGN(s->gsi_count, 32) / 32;
-    int i, bit;
-    uint32_t *buf = s->used_gsi_bitmap;
-
-    /* Return the lowest unused GSI in the bitmap */
-    for (i = 0; i < max_words; i++) {
-        bit = ffs(~buf[i]);
-        if (!bit) {
-            continue;
-        }
-
-        return bit - 1 + i * 32;
-    }
-
-    return -ENOSPC;
-#else
-    return -ENOSYS;
-#endif
-}
-
 #if !defined(TARGET_I386)
 void kvm_arch_init_irq_routing(KVMState *s)
 {
diff --git a/qemu-kvm.h b/qemu-kvm.h
index ad628d5..ae7a33c 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -43,28 +43,6 @@
  */
 int kvm_assign_irq(KVMState *s, struct kvm_assigned_irq *assigned_irq);
 
-struct kvm_irq_routing_entry;
-
-void kvm_add_routing_entry(KVMState *s, struct kvm_irq_routing_entry *entry);
-
-/*!
- * \brief Removes a routing from the temporary irq routing table
- *
- * Remove a routing to the temporary irq routing table.  Nothing is
- * committed to the running VM.
- */
-int kvm_del_routing_entry(struct kvm_irq_routing_entry *entry);
-
-/*!
- * \brief Updates a routing in the temporary irq routing table
- *
- * Update a routing in the temporary irq routing table
- * with a new value. entry type and GSI can not be changed.
- * Nothing is committed to the running VM.
- */
-int kvm_update_routing_entry(struct kvm_irq_routing_entry *entry,
-                             struct kvm_irq_routing_entry *newentry);
-
 #endif /* CONFIG_KVM */
 
 #endif
-- 
1.7.3.4

--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html


[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux