From ebb540ebeece2e934989c9f5944371cb5f0ae073 Mon Sep 17 00:00:00 2001
Message-Id: <ebb540ebeece2e934989c9f5944371cb5f0ae073.1371733794.git.minovotn@redhat.com>
In-Reply-To: <c4dd58cee9e41e408664060ffa819156649c7cb3.1371733794.git.minovotn@redhat.com>
References: <c4dd58cee9e41e408664060ffa819156649c7cb3.1371733794.git.minovotn@redhat.com>
From: Alex Williamson <alex.williamson@redhat.com>
Date: Thu, 23 May 2013 22:23:04 +0200
Subject: [PATCH 2/6] pci-assign: Add MSI affinity support

RH-Author: Alex Williamson <alex.williamson@redhat.com>
Message-id: <20130523222304.23855.86099.stgit@bling.home>
Patchwork-id: 51615
O-Subject: [RHEL6.5 -E qemu-kvm PATCH] pci-assign: Add MSI affinity support
Bugzilla: 919761
RH-Acked-by: Laszlo Ersek <lersek@redhat.com>
RH-Acked-by: Michael S. Tsirkin <mst@redhat.com>
RH-Acked-by: Don Dutile <ddutile@redhat.com>

Bugzilla: 919761
Upstream commit: 3459f01b2d9612070ec23221a4ccb60a41b775ae (qemu.git)
Testing:
  Tested with e1000e 82578DM supporting MSI/INTx-only.  Without this,
  RHEL5 guests do nothing on IRQ smp_affinity update because MSI
  enable isn't toggled.  RHEL6 guests do toggle MSI enabled, but the
  sequence it uses causes smp_affinity to use the previous CPU
  targets, so two updates are required to get the desired targets.
  With patch both work as expected.
Backport notes:
  Code is significantly different from upstream.  Compare to
  assigned_dev_update_msi for creating routing entry and extracting
  address/data from the MSI capability and msix_mmio_writel for
  performing an update of a routing entry.
Brew: https://brewweb.devel.redhat.com/taskinfo?taskID=5820217

To support guest MSI affinity changes update the MSI message any time
the guest writes to the address or data fields.

Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
Acked-by: Michael S. Tsirkin <mst@redhat.com>
Message-id: 20130513201840.5430.86331.stgit@bling.home
Signed-off-by: Anthony Liguori <aliguori@us.ibm.com>
---
 hw/device-assignment.c |   50 ++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

Signed-off-by: Michal Novotny <minovotn@redhat.com>
---
 hw/device-assignment.c | 50 ++++++++++++++++++++++++++++++++++++++++++++++++++
 1 file changed, 50 insertions(+)

diff --git a/hw/device-assignment.c b/hw/device-assignment.c
index 9d8d39e..4cc27a2 100644
--- a/hw/device-assignment.c
+++ b/hw/device-assignment.c
@@ -1132,6 +1132,53 @@ static void assigned_dev_update_msi(PCIDevice *pci_dev, unsigned int ctrl_pos)
         assigned_dev->irq_requested_type = assigned_irq_data.flags;
     }
 }
+
+static void assigned_dev_update_msi_msg(PCIDevice *pci_dev,
+                                        unsigned int ctrl_pos)
+{
+    AssignedDevice *assigned_dev = container_of(pci_dev, AssignedDevice, dev);
+    uint8_t ctrl_byte = pci_dev->config[ctrl_pos];
+    struct kvm_irq_routing_entry *orig;
+    int pos, ret;
+
+    if (!(assigned_dev->irq_requested_type & KVM_DEV_IRQ_GUEST_MSI) ||
+        !(ctrl_byte & PCI_MSI_FLAGS_ENABLE)) {
+        return;
+    }
+
+    orig = assigned_dev->entry;
+    pos = ctrl_pos - PCI_MSI_FLAGS;
+
+    assigned_dev->entry = calloc(1, sizeof(struct kvm_irq_routing_entry));
+    if (!assigned_dev->entry) {
+        assigned_dev->entry = orig;
+        perror("assigned_dev_update_msi_msg: ");
+        return;
+    }
+
+    assigned_dev->entry->u.msi.address_lo =
+                    pci_get_long(pci_dev->config + pos + PCI_MSI_ADDRESS_LO);
+    assigned_dev->entry->u.msi.address_hi = 0;
+    assigned_dev->entry->u.msi.data =
+                    pci_get_word(pci_dev->config + pos + PCI_MSI_DATA_32);
+    assigned_dev->entry->type = KVM_IRQ_ROUTING_MSI;
+    assigned_dev->entry->gsi = orig->gsi;
+
+    ret = kvm_update_routing_entry(kvm_context, orig, assigned_dev->entry);
+    if (ret) {
+        fprintf(stderr, "Error updating MSI irq routing entry (%d)\n", ret);
+        free(assigned_dev->entry);
+        assigned_dev->entry = orig;
+        return;
+    }
+
+    free(orig);
+
+    ret = kvm_commit_irq_routes(kvm_context);
+    if (ret) {
+        fprintf(stderr, "Error committing MSI irq route (%d)\n", ret);
+    }
+}
 #endif
 
 #ifdef KVM_CAP_DEVICE_MSIX
@@ -1362,6 +1409,9 @@ static void assigned_device_pci_cap_write_config(PCIDevice *pci_dev,
             uint8_t cap = pci_find_capability(pci_dev, cap_id);
             if (ranges_overlap(address - cap, len, PCI_MSI_FLAGS, 1)) {
                 assigned_dev_update_msi(pci_dev, cap + PCI_MSI_FLAGS);
+            } else if (ranges_overlap(address - cap, len, /* 32bit MSI only */
+                                      PCI_MSI_ADDRESS_LO, 6)) {
+                assigned_dev_update_msi_msg(pci_dev, cap + PCI_MSI_FLAGS);
             }
         }
 #endif
-- 
1.7.11.7

