On 30/1/25 14:43, Cédric Le Goater wrote:
Print a warning if IOMMU address space width is smaller than the
physical address width. In this case, PCI peer-to-peer transactions on
BARs are not supported and failures of device MMIO regions are to be
expected.

This can occur with the 39-bit IOMMU address space width as found on
consumer grade processors or when using a vIOMMU device with default
settings.

Signed-off-by: Cédric Le Goater <c...@redhat.com>
---
  hw/vfio/common.c | 21 +++++++++++++++++++++
  1 file changed, 21 insertions(+)

diff --git a/hw/vfio/common.c b/hw/vfio/common.c
index 
5c9d8657d746ce30af5ae8f9122101e086a61ef5..e5ef93c589b2bed68f790608868ec3c7779d4cb8
 100644
--- a/hw/vfio/common.c
+++ b/hw/vfio/common.c
@@ -44,6 +44,8 @@
  #include "migration/qemu-file.h"
  #include "system/tpm.h"
+#include "hw/core/cpu.h"
+
  VFIODeviceList vfio_device_list =
      QLIST_HEAD_INITIALIZER(vfio_device_list);
  static QLIST_HEAD(, VFIOAddressSpace) vfio_address_spaces =
@@ -1546,12 +1548,28 @@ retry:
      return info;
  }
+static bool vfio_device_check_address_space(VFIODevice *vbasedev, Error **errp)
+{
+    uint32_t cpu_aw_bits = cpu_get_phys_bits(first_cpu);

This 'first_cpu' use is annoying. I understand the device is created
from the CLI, and passing the host physical bits limit as a device
property is not practical. We'll deal with that later...

+    uint32_t iommu_aw_bits = vfio_device_get_aw_bits(vbasedev);
+
+    if (cpu_aw_bits && cpu_aw_bits > iommu_aw_bits) {
+        error_setg(errp, "Host physical address space (%u) is larger than "
+                   "the host IOMMU address space (%u).", cpu_aw_bits,
+                   iommu_aw_bits);
+        vfio_device_error_append(vbasedev, errp);
+        return false;
+    }
+    return true;
+}
+
  bool vfio_attach_device(char *name, VFIODevice *vbasedev,
                          AddressSpace *as, Error **errp)
  {
      const VFIOIOMMUClass *ops =
          VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_LEGACY));
      HostIOMMUDevice *hiod = NULL;
+    Error *local_err = NULL;
if (vbasedev->iommufd) {
          ops = VFIO_IOMMU_CLASS(object_class_by_name(TYPE_VFIO_IOMMU_IOMMUFD));
@@ -1571,6 +1589,9 @@ bool vfio_attach_device(char *name, VFIODevice *vbasedev,
          return false;
      }
+ if (!vfio_device_check_address_space(vbasedev, &local_err)) {
+        warn_report_err(local_err);
+    }
      return true;
  }


Reply via email to