Patchwork [RFC,20/45] qemu-kvm: msix: Only invoke msix_handle_mask_update on changes

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

Comments

Jan Kiszka - Oct. 17, 2011, 9:27 a.m.
Reorganize msix_mmio_writel so that msix_handle_mask_update is only
called on mask changes. Pass previous config space value to
msix_write_config so that is can check if a mask change took place.

Signed-off-by: Jan Kiszka <jan.kiszka@siemens.com>
---
 hw/msix.c |   36 ++++++++++++++++++++----------------
 hw/msix.h |    2 +-
 hw/pci.c  |    3 ++-
 3 files changed, 23 insertions(+), 18 deletions(-)

Patch

diff --git a/hw/msix.c b/hw/msix.c
index 6886255..57d0aac 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -206,12 +206,12 @@  static void msix_clr_pending(PCIDevice *dev, int vector)
     *msix_pending_byte(dev, vector) &= ~msix_pending_mask(vector);
 }
 
-static int msix_function_masked(PCIDevice *dev)
+static bool msix_function_masked(PCIDevice *dev)
 {
     return dev->config[dev->msix_cap + MSIX_CONTROL_OFFSET] & MSIX_MASKALL_MASK;
 }
 
-static int msix_is_masked(PCIDevice *dev, int vector)
+static bool msix_is_masked(PCIDevice *dev, int vector)
 {
     unsigned offset =
         vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
@@ -229,9 +229,10 @@  static void msix_handle_mask_update(PCIDevice *dev, int vector)
 
 /* Handle MSI-X capability config write. */
 void msix_write_config(PCIDevice *dev, uint32_t addr,
-                       uint32_t val, int len)
+                       uint32_t old_val, int len)
 {
     unsigned enable_pos = dev->msix_cap + MSIX_CONTROL_OFFSET;
+    bool was_masked;
     int vector;
 
     if (!msix_present(dev) || !range_covers_byte(addr, len, enable_pos)) {
@@ -244,12 +245,13 @@  void msix_write_config(PCIDevice *dev, uint32_t addr,
 
     pci_device_deassert_intx(dev);
 
-    if (msix_function_masked(dev)) {
-        return;
-    }
-
-    for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
-        msix_handle_mask_update(dev, vector);
+    old_val >>= (enable_pos - addr) * 8;
+    was_masked =
+        (old_val & (MSIX_MASKALL_MASK | MSIX_ENABLE_MASK)) != MSIX_ENABLE_MASK;
+    if (was_masked != msix_function_masked(dev)) {
+        for (vector = 0; vector < dev->msix_entries_nr; ++vector) {
+            msix_handle_mask_update(dev, vector);
+        }
     }
 }
 
@@ -259,17 +261,19 @@  static void msix_mmio_write(void *opaque, target_phys_addr_t addr,
     PCIDevice *dev = opaque;
     unsigned int offset = addr & (MSIX_PAGE_SIZE - 1) & ~0x3;
     unsigned int vector = offset / PCI_MSIX_ENTRY_SIZE;
-    int was_masked = msix_is_masked(dev, vector);
+    bool was_masked = msix_is_masked(dev, vector);
+    int r;
+
     pci_set_long(dev->msix_table_page + offset, val);
     if (kvm_enabled() && kvm_irqchip_in_kernel()) {
         kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
     }
 
-    if (vector < dev->msix_entries_nr) {
-        if (was_masked != msix_is_masked(dev, vector) &&
-            dev->msix_mask_notifier) {
-            int r = dev->msix_mask_notifier(dev, vector,
-                                            msix_is_masked(dev, vector));
+    if (vector < dev->msix_entries_nr &&
+        was_masked != msix_is_masked(dev, vector)) {
+        if (dev->msix_mask_notifier) {
+            r = dev->msix_mask_notifier(dev, vector,
+                                        msix_is_masked(dev, vector));
             assert(r >= 0);
         }
         msix_handle_mask_update(dev, vector);
@@ -303,7 +307,7 @@  static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
     for (vector = 0; vector < nentries; ++vector) {
         unsigned offset =
             vector * PCI_MSIX_ENTRY_SIZE + PCI_MSIX_ENTRY_VECTOR_CTRL;
-        int was_masked = msix_is_masked(dev, vector);
+        bool was_masked = msix_is_masked(dev, vector);
         dev->msix_table_page[offset] |= PCI_MSIX_ENTRY_CTRL_MASKBIT;
         if (was_masked != msix_is_masked(dev, vector) &&
             dev->msix_mask_notifier) {
diff --git a/hw/msix.h b/hw/msix.h
index a8661e1..685dbe2 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -9,7 +9,7 @@  int msix_init(PCIDevice *pdev, unsigned short nentries,
               unsigned bar_nr, unsigned bar_size);
 
 void msix_write_config(PCIDevice *pci_dev, uint32_t address,
-                       uint32_t val, int len);
+                       uint32_t old_val, int len);
 
 int msix_uninit(PCIDevice *d, MemoryRegion *bar);
 
diff --git a/hw/pci.c b/hw/pci.c
index 6673989..39b2173 100644
--- a/hw/pci.c
+++ b/hw/pci.c
@@ -1129,6 +1129,7 @@  uint32_t pci_default_read_config(PCIDevice *d,
 
 void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
 {
+    uint32_t old_val = pci_default_read_config(d, addr, l);
     int i, was_irq_disabled = pci_irq_disabled(d);
 
     for (i = 0; i < l; val >>= 8, ++i) {
@@ -1156,7 +1157,7 @@  void pci_default_write_config(PCIDevice *d, uint32_t addr, uint32_t val, int l)
         pci_update_irq_disabled(d, was_irq_disabled);
 
     msi_write_config(d, addr, val, l);
-    msix_write_config(d, addr, val, l);
+    msix_write_config(d, addr, old_val, l);
 }
 
 /***********************************************************/