summary refs log tree commit diff stats
diff options
context:
space:
mode:
-rw-r--r--hw/vfio/common.c15
-rw-r--r--hw/vfio/pci.c9
-rw-r--r--include/hw/vfio/vfio-common.h1
3 files changed, 25 insertions, 0 deletions
diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 07c03d78b6..5e84716218 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -1471,6 +1471,21 @@ int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
     return -ENODEV;
 }
 
+bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type)
+{
+    struct vfio_region_info *info = NULL;
+    bool ret = false;
+
+    if (!vfio_get_region_info(vbasedev, region, &info)) {
+        if (vfio_get_region_info_cap(info, cap_type)) {
+            ret = true;
+        }
+        g_free(info);
+    }
+
+    return ret;
+}
+
 /*
  * Interfaces for IBM EEH (Enhanced Error Handling)
  */
diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c
index b9d2c12b82..02974f4eb9 100644
--- a/hw/vfio/pci.c
+++ b/hw/vfio/pci.c
@@ -1295,6 +1295,15 @@ static void vfio_pci_fixup_msix_region(VFIOPCIDevice *vdev)
     VFIORegion *region = &vdev->bars[vdev->msix->table_bar].region;
 
     /*
+     * If the host driver allows mapping of a MSIX data, we are going to
+     * do map the entire BAR and emulate MSIX table on top of that.
+     */
+    if (vfio_has_region_cap(&vdev->vbasedev, region->nr,
+                            VFIO_REGION_INFO_CAP_MSIX_MAPPABLE)) {
+        return;
+    }
+
+    /*
      * We expect to find a single mmap covering the whole BAR, anything else
      * means it's either unsupported or already setup.
      */
diff --git a/include/hw/vfio/vfio-common.h b/include/hw/vfio/vfio-common.h
index c5efa32750..d9360148e6 100644
--- a/include/hw/vfio/vfio-common.h
+++ b/include/hw/vfio/vfio-common.h
@@ -193,6 +193,7 @@ int vfio_get_region_info(VFIODevice *vbasedev, int index,
                          struct vfio_region_info **info);
 int vfio_get_dev_region_info(VFIODevice *vbasedev, uint32_t type,
                              uint32_t subtype, struct vfio_region_info **info);
+bool vfio_has_region_cap(VFIODevice *vbasedev, int region, uint16_t cap_type);
 #endif
 extern const MemoryListener vfio_prereg_listener;