diff mbox

[07/19] pci-assign: Rework MSI assignment

Message ID 4941e4708e501dd9ed4dafe6bfd973813059857b.1345125266.git.jan.kiszka@siemens.com (mailing list archive)
State New, archived
Headers show

Commit Message

Jan Kiszka Aug. 16, 2012, 1:54 p.m. UTC
Introduce kvm_device_msi_assign and use upstream's
kvm_irqchip_add_msi_route/kvm_irqchip_release_virq to provide MSI
support for assigned devices.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/device-assignment.c |   54 +++++++++++++++++++++++++----------------------
 target-i386/kvm.c      |    6 +++++
 target-i386/kvm_i386.h |    1 +
 3 files changed, 36 insertions(+), 25 deletions(-)
diff mbox

Patch

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index d448fdc..1d0af34 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -41,6 +41,7 @@ 
 #include "range.h"
 #include "sysemu.h"
 #include "pci.h"
+#include "msi.h"
 #include "kvm_i386.h"
 
 #define MSIX_PAGE_SIZE 0x1000
@@ -138,6 +139,8 @@  typedef struct AssignedDevice {
     } cap;
     uint8_t emulate_config_read[PCI_CONFIG_SPACE_SIZE];
     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;
@@ -702,6 +705,16 @@  static void free_dev_irq_entries(AssignedDevice *dev)
 {
     int i;
 
+    for (i = 0; i < dev->msi_virq_nr; i++) {
+        if (dev->msi_virq[i] >= 0) {
+            kvm_irqchip_release_virq(kvm_state, dev->msi_virq[i]);
+            dev->msi_virq[i] = -1;
+        }
+    }
+    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]);
@@ -973,7 +986,6 @@  static void assigned_dev_update_irq_routing(PCIDevice *dev)
 
 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);
     uint8_t ctrl_byte = pci_get_byte(pci_dev->config + pci_dev->msi_cap +
                                      PCI_MSI_FLAGS);
@@ -984,43 +996,35 @@  static void assigned_dev_update_msi(PCIDevice *pci_dev)
      * MSI or intends to start. */
     if (assigned_dev->assigned_irq_type == ASSIGNED_IRQ_MSI ||
         (ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
-
-        free_dev_irq_entries(assigned_dev);
         r = kvm_device_msi_deassign(kvm_state, assigned_dev->dev_id);
         /* -ENXIO means no assigned irq */
         if (r && r != -ENXIO)
             perror("assigned_dev_update_msi: deassign irq");
 
+        free_dev_irq_entries(assigned_dev);
+
         assigned_dev->assigned_irq_type = ASSIGNED_IRQ_NONE;
         pci_device_set_intx_routing_notifier(pci_dev, NULL);
     }
 
     if (ctrl_byte & PCI_MSI_FLAGS_ENABLE) {
         uint8_t *pos = pci_dev->config + pci_dev->msi_cap;
-
-        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");
+        MSIMessage msg;
+        int virq;
+
+        msg.address = pci_get_long(pos + PCI_MSI_ADDRESS_LO);
+        msg.data = pci_get_word(pos + PCI_MSI_DATA_32);
+        virq = kvm_irqchip_add_msi_route(kvm_state, msg);
+        if (virq < 0) {
+            perror("assigned_dev_update_msi: kvm_irqchip_add_msi_route");
             return;
         }
-        assigned_dev->entry->gsi = r;
 
-        kvm_add_routing_entry(kvm_state, assigned_dev->entry);
-        kvm_irqchip_commit_routes(kvm_state);
-	assigned_dev->irq_entries_nr = 1;
-
-        memset(&assigned_irq_data, 0, sizeof assigned_irq_data);
-        assigned_irq_data.assigned_dev_id = assigned_dev->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");
+        assigned_dev->msi_virq = g_malloc(sizeof(*assigned_dev->msi_virq));
+        assigned_dev->msi_virq_nr = 1;
+        assigned_dev->msi_virq[0] = virq;
+        if (kvm_device_msi_assign(kvm_state, assigned_dev->dev_id, virq) < 0) {
+            perror("assigned_dev_update_msi: kvm_device_msi_assign");
         }
 
         assigned_dev->intx_route.mode = PCI_INTX_DISABLED;
diff --git a/target-i386/kvm.c b/target-i386/kvm.c
index 4941744..04d1c7d 100644
--- a/target-i386/kvm.c
+++ b/target-i386/kvm.c
@@ -2142,6 +2142,12 @@  int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi)
         (use_host_msi ? KVM_DEV_IRQ_HOST_MSI : KVM_DEV_IRQ_HOST_INTX));
 }
 
+int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq)
+{
+    return kvm_assign_irq_internal(s, dev_id, KVM_DEV_IRQ_HOST_MSI |
+                                              KVM_DEV_IRQ_GUEST_MSI, virq);
+}
+
 int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id)
 {
     return kvm_deassign_irq_internal(s, dev_id, KVM_DEV_IRQ_GUEST_MSI |
diff --git a/target-i386/kvm_i386.h b/target-i386/kvm_i386.h
index 28f26bb..e827f5b 100644
--- a/target-i386/kvm_i386.h
+++ b/target-i386/kvm_i386.h
@@ -24,6 +24,7 @@  int kvm_device_intx_assign(KVMState *s, uint32_t dev_id,
 int kvm_device_intx_set_mask(KVMState *s, uint32_t dev_id, bool masked);
 int kvm_device_intx_deassign(KVMState *s, uint32_t dev_id, bool use_host_msi);
 
+int kvm_device_msi_assign(KVMState *s, uint32_t dev_id, int virq);
 int kvm_device_msi_deassign(KVMState *s, uint32_t dev_id);
 
 int kvm_device_msix_deassign(KVMState *s, uint32_t dev_id);