diff mbox

[PATCHv6,3/4] msix: add mask/unmask notifiers

Message ID ccb3c2d6a3c33908f033f0f3c79cfa53f07d415d.1268831034.git.mst@redhat.com (mailing list archive)
State New, archived
Headers show

Commit Message

Michael S. Tsirkin March 17, 2010, 1:04 p.m. UTC
None
diff mbox

Patch

diff --git a/hw/msix.c b/hw/msix.c
index faee0b2..3ec8805 100644
--- a/hw/msix.c
+++ b/hw/msix.c
@@ -317,6 +317,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);
 }
 
@@ -355,10 +362,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);
+        }
     }
 }
 
@@ -381,6 +396,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);
 
@@ -443,6 +461,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;
 }
@@ -586,3 +606,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 1eab8f2..100104c 100644
--- a/hw/pci.h
+++ b/hw/pci.h
@@ -136,6 +136,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 */
@@ -201,6 +204,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;