Patchwork [RFC,34/45] qemu-kvm: Factor out kvm_device_msi_assign

login
register
mail settings
Submitter Jan Kiszka
Date Oct. 17, 2011, 9:28 a.m.
Message ID <93a318fd890a49e0259e8888a3dd82f25716bca3.1318843693.git.jan.kiszka@siemens.com>
Download mbox | patch
Permalink /patch/120151/
State New
Headers show

Comments

Jan Kiszka - Oct. 17, 2011, 9:28 a.m.
This reuses the MSI routing infrastructure of the KVM core by folding
both the routing setup and the IRQ assignment into a new function called
kvm_device_msi_assign. It's also a good chance to clean up the IRQ
deassignment before updates.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/device-assignment.c |   70 +++++++++++++----------------------------------
 qemu-kvm.c             |   16 +++++++++++
 qemu-kvm.h             |    2 +
 3 files changed, 38 insertions(+), 50 deletions(-)

Patch

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index f145a84..7a8f702 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -40,6 +40,7 @@ 
 #include "monitor.h"
 #include "range.h"
 #include "sysemu.h"
+#include "msi.h"
 
 #define MSIX_PAGE_SIZE 0x1000
 
@@ -701,6 +702,11 @@  static void free_assigned_device(AssignedDevice *dev)
     }
 
     free_dev_irq_entries(dev);
+
+    if (dev->dev.msi_cache) {
+        kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]);
+        g_free(dev->dev.msi_cache);
+    }
 }
 
 static uint32_t calc_assigned_dev_id(AssignedDevice *dev)
@@ -918,66 +924,28 @@  void assigned_dev_update_irqs(void)
 
 static void assigned_dev_update_msi(PCIDevice *pci_dev)
 {
-    struct kvm_assigned_irq assigned_irq_data;
-    AssignedDevice *assigned_dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
+    AssignedDevice *dev = DO_UPCAST(AssignedDevice, dev, pci_dev);
     uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
                                      PCI_MSI_FLAGS);
-    uint32_t dev_id;
-    int r;
-
-    dev_id = calc_assigned_dev_id(assigned_dev);
-
-    /* Some guests gratuitously disable MSI even if they're not using it,
-     * try to catch this by only deassigning irqs if the guest is using
-     * MSI or intends to start. */
-    if ((assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSI) ||
-        (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
-        free_dev_irq_entries(assigned_dev);
-        r = kvm_device_irq_deassign(kvm_state, dev_id,
-                                    assigned_dev->irq_requested_type);
-        /* -ENXIO means no assigned irq */
-        if (r && r != -ENXIO)
-            perror("assigned_dev_update_msi: deassign irq");
-
-        assigned_dev->irq_requested_type = 0;
-    }
 
     if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
         uint8_t *pos = pci_dev->config + pci_dev->msi_cap;
+        MSIMessage msg;
 
-        assigned_dev->entry = g_malloc0(sizeof(*(assigned_dev->entry)));
-        assigned_dev->entry->u.msi.address_lo =
-            pci_get_long(pos + PCI_MSI_ADDRESS_LO);
-        assigned_dev->entry->u.msi.address_hi = 0;
-        assigned_dev->entry->u.msi.data = pci_get_word(pos + PCI_MSI_DATA_32);
-        assigned_dev->entry->type = KVM_IRQ_ROUTING_MSI;
-        r = kvm_get_irq_route_gsi();
-        if (r < 0) {
-            perror("assigned_dev_update_msi: kvm_get_irq_route_gsi");
-            return;
-        }
-        assigned_dev->entry->gsi = r;
+        deassign_irq(dev);
 
-        kvm_add_routing_entry(assigned_dev->entry, NULL);
-        if (kvm_commit_irq_routes() < 0) {
-            perror("assigned_dev_update_msi: kvm_commit_irq_routes");
-            assigned_dev->cap.state &= ~ASSIGNED_DEVICE_MSI_ENABLED;
-            return;
-        }
-	assigned_dev->irq_entries_nr = 1;
+        msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO);
+        msg.data = pci_get_word(pos + PCI_MSI_DATA_32);
 
-        memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
-        assigned_irq_data.assigned_dev_id = dev_id;
-        assigned_irq_data.guest_irq = assigned_dev->entry->gsi;
-	assigned_irq_data.flags = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI;
-        if (kvm_assign_irq(kvm_state, &assigned_irq_data) < 0) {
-            perror("assigned_dev_enable_msi: assign irq");
+        if (kvm_device_msi_assign(kvm_state, calc_assigned_dev_id(dev), &msg,
+                                  &dev->dev.msi_cache[0]) < 0) {
+            perror("assigned_dev_update_msi: assign msi");
+            return;
         }
-
-        assigned_dev->girq = -1;
-        assigned_dev->irq_requested_type = assigned_irq_data.flags;
+        dev->irq_requested_type = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI;
     } else {
-        assign_intx(assigned_dev);
+        kvm_msi_cache_invalidate(&dev->dev.msi_cache[0]);
+        assign_intx(dev);
     }
 }
 
@@ -1215,6 +1183,8 @@  static int assigned_device_pci_cap_init(PCIDevice *pci_dev)
                      PCI_MSI_FLAGS_QSIZE | PCI_MSI_FLAGS_ENABLE);
         pci_set_long(pci_dev->wmask + pos + PCI_MSI_ADDRESS_LO, 0xfffffffc);
         pci_set_word(pci_dev->wmask + pos + PCI_MSI_DATA_32, 0xffff);
+
+        dev->dev.msi_cache = g_malloc0(sizeof(MSIRoutingCache));
     }
     /* Expose MSI-X capability */
     pos = pci_find_cap_offset(pci_dev, PCI_CAP_ID_MSIX, 0);
diff --git a/qemu-kvm.c b/qemu-kvm.c
index 0086514..27723a6 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -600,6 +600,22 @@  int kvm_msi_irqfd_set(MSIMessage *msg, MSIRoutingCache *cache, int fd,
     return kvm_set_irqfd(cache->kvm_gsi, fd, assigned);
 }
 
+int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, MSIMessage *msg,
+                          MSIRoutingCache *cache)
+{
+    struct kvm_assigned_irq assigned_irq;
+    int ret;
+
+    ret = kvm_msi_message_update(msg, cache, MSI_ROUTE_STATIC);
+    if (ret < 0) {
+        return ret;
+    }
+    assigned_irq.assigned_dev_id = dev_id;
+    assigned_irq.guest_irq = cache->kvm_gsi;
+    assigned_irq.flags = KVM_DEV_IRQ_HOST_MSI | KVM_DEV_IRQ_GUEST_MSI;
+    return kvm_vm_ioctl(s, KVM_ASSIGN_DEV_IRQ, &assigned_irq);
+}
+
 #ifdef KVM_CAP_DEVICE_MSIX
 int kvm_assign_set_msix_nr(KVMState *s, struct kvm_assigned_msix_nr *msix_nr)
 {
diff --git a/qemu-kvm.h b/qemu-kvm.h
index 783df7f..d987d41 100644
--- a/qemu-kvm.h
+++ b/qemu-kvm.h
@@ -152,6 +152,8 @@  int kvm_assign_irq(KVMState *s, struct kvm_assigned_irq *assigned_irq);
 
 int kvm_device_intx_assign(KVMState *s, uint32_t dev_id,
                            uint32_t host_irq_type, uint32_t guest_irq);
+int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, MSIMessage *msg,
+                          MSIRoutingCache *cache);
 int kvm_device_irq_deassign(KVMState *s, uint32_t dev_id, uint32_t type);
 
 /*!