Blob Blame History Raw
Support per-vector callbacks for msix mask/unmask.
Will be used for vhost net.

Signed-off-by: Michael S. Tsirkin <mst@redhat.com>
---
 hw/msix.c |   36 +++++++++++++++++++++++++++++++++++-
 hw/msix.h |    1 +
 hw/pci.h  |    6 ++++++
 3 files changed, 42 insertions(+), 1 deletions(-)

diff --git a/hw/msix.c b/hw/msix.c
index d117bcf..3fcf3a1 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -318,6 +318,13 @@ static void msix_mmio_writel(void *opaque, target_phys_addr_t addr,
     if (kvm_enabled() && kvm_irqchip_in_kernel()) {
         kvm_msix_update(dev, vector, was_masked, msix_is_masked(dev, vector));
     }
+    if (was_masked != msix_is_masked(dev, vector) &&
+        dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
+        int r = dev->msix_mask_notifier(dev, vector,
+					dev->msix_mask_notifier_opaque[vector],
+					msix_is_masked(dev, vector));
+        assert(r >= 0);
+    }
     msix_handle_mask_update(dev, vector);
 }
 
@@ -356,10 +363,18 @@ void msix_mmio_map(PCIDevice *d, int region_num,
 
 static void msix_mask_all(struct PCIDevice *dev, unsigned nentries)
 {
-    int vector;
+    int vector, r;
     for (vector = 0; vector < nentries; ++vector) {
         unsigned offset = vector * MSIX_ENTRY_SIZE + MSIX_VECTOR_CTRL;
+        int was_masked = msix_is_masked(dev, vector);
         dev->msix_table_page[offset] |= MSIX_VECTOR_MASK;
+        if (was_masked != msix_is_masked(dev, vector) &&
+            dev->msix_mask_notifier && dev->msix_mask_notifier_opaque[vector]) {
+            r = dev->msix_mask_notifier(dev, vector,
+                                        dev->msix_mask_notifier_opaque[vector],
+                                        msix_is_masked(dev, vector));
+            assert(r >= 0);
+        }
     }
 }
 
@@ -382,6 +397,9 @@ int msix_init(struct PCIDevice *dev, unsigned short nentries,
                                             sizeof *dev->msix_irq_entries);
     }
 #endif
+    dev->msix_mask_notifier_opaque =
+        qemu_mallocz(nentries * sizeof *dev->msix_mask_notifier_opaque);
+    dev->msix_mask_notifier = NULL;
     dev->msix_entry_used = qemu_mallocz(MSIX_MAX_ENTRIES *
                                         sizeof *dev->msix_entry_used);
 
@@ -444,6 +462,8 @@ int msix_uninit(PCIDevice *dev)
     dev->msix_entry_used = NULL;
     qemu_free(dev->msix_irq_entries);
     dev->msix_irq_entries = NULL;
+    qemu_free(dev->msix_mask_notifier_opaque);
+    dev->msix_mask_notifier_opaque = NULL;
     dev->cap_present &= ~QEMU_PCI_CAP_MSIX;
     return 0;
 }
@@ -587,3 +607,17 @@ void msix_unuse_all_vectors(PCIDevice *dev)
         return;
     msix_free_irq_entries(dev);
 }
+
+int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque)
+{
+    int r = 0;
+    if (vector >= dev->msix_entries_nr || !dev->msix_entry_used[vector])
+        return 0;
+
+    if (dev->msix_mask_notifier)
+        r = dev->msix_mask_notifier(dev, vector, opaque,
+                                    msix_is_masked(dev, vector));
+    if (r >= 0)
+        dev->msix_mask_notifier_opaque[vector] = opaque;
+    return r;
+}
diff --git a/hw/msix.h b/hw/msix.h
index a9f7993..f167231 100644
--- a/hw/msix.h
+++ b/hw/msix.h
@@ -33,4 +33,5 @@ void msix_reset(PCIDevice *dev);
 
 extern int msix_supported;
 
+int msix_set_mask_notifier(PCIDevice *dev, unsigned vector, void *opaque);
 #endif
diff --git a/hw/pci.h b/hw/pci.h
index a225a6a..bf722ca 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -217,6 +217,9 @@ enum {
 #define PCI_CAPABILITY_CONFIG_MSI_LENGTH 0x10
 #define PCI_CAPABILITY_CONFIG_MSIX_LENGTH 0x10
 
+typedef int (*msix_mask_notifier_func)(PCIDevice *, unsigned vector,
+				       void *opaque, int masked);
+
 struct PCIDevice {
     DeviceState qdev;
     /* PCI config space */
@@ -282,6 +285,9 @@ struct PCIDevice {
 
     struct kvm_irq_routing_entry *msix_irq_entries;
 
+    void **msix_mask_notifier_opaque;
+    msix_mask_notifier_func msix_mask_notifier;
+
     /* Device capability configuration space */
     struct {
         int supported;
-- 
1.6.6.144.g5c3af