]> git.proxmox.com Git - mirror_qemu.git/blobdiff - hw/vfio/pci-quirks.c
error: Eliminate error_propagate() with Coccinelle, part 1
[mirror_qemu.git] / hw / vfio / pci-quirks.c
index f2155ddb1d7891a75b4be69ea4dff7b6069e3ea5..3a14b7c30323f725d60844b84a18ab69c73c3a63 100644 (file)
@@ -11,6 +11,7 @@
  */
 
 #include "qemu/osdep.h"
+#include "config-devices.h"
 #include "exec/memop.h"
 #include "qemu/units.h"
 #include "qemu/error-report.h"
@@ -1501,16 +1502,13 @@ static void set_nv_gpudirect_clique_id(Object *obj, Visitor *v,
     DeviceState *dev = DEVICE(obj);
     Property *prop = opaque;
     uint8_t value, *ptr = qdev_get_prop_ptr(dev, prop);
-    Error *local_err = NULL;
 
     if (dev->realized) {
         qdev_prop_set_after_realize(dev, name, errp);
         return;
     }
 
-    visit_type_uint8(v, name, &value, &local_err);
-    if (local_err) {
-        error_propagate(errp, local_err);
+    if (!visit_type_uint8(v, name, &value, errp)) {
         return;
     }
 
@@ -1567,18 +1565,6 @@ static int vfio_add_nv_gpudirect_cap(VFIOPCIDevice *vdev, Error **errp)
     return 0;
 }
 
-int vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp)
-{
-    int ret;
-
-    ret = vfio_add_nv_gpudirect_cap(vdev, errp);
-    if (ret) {
-        return ret;
-    }
-
-    return 0;
-}
-
 static void vfio_pci_nvlink2_get_tgt(Object *obj, Visitor *v,
                                      const char *name,
                                      void *opaque, Error **errp)
@@ -1709,3 +1695,75 @@ free_exit:
 
     return ret;
 }
+
+/*
+ * The VMD endpoint provides a real PCIe domain to the guest and the guest
+ * kernel performs enumeration of the VMD sub-device domain. Guest transactions
+ * to VMD sub-devices go through MMU translation from guest addresses to
+ * physical addresses. When MMIO goes to an endpoint after being translated to
+ * physical addresses, the bridge rejects the transaction because the window
+ * has been programmed with guest addresses.
+ *
+ * VMD can use the Host Physical Address in order to correctly program the
+ * bridge windows in its PCIe domain. VMD device 28C0 has HPA shadow registers
+ * located at offset 0x2000 in MEMBAR2 (BAR 4). This quirk provides the HPA
+ * shadow registers in a vendor-specific capability register for devices
+ * without native support. The position of 0xE8-0xFF is in the reserved range
+ * of the VMD device capability space following the Power Management
+ * Capability.
+ */
+#define VMD_SHADOW_CAP_VER 1
+#define VMD_SHADOW_CAP_LEN 24
+static int vfio_add_vmd_shadow_cap(VFIOPCIDevice *vdev, Error **errp)
+{
+    uint8_t membar_phys[16];
+    int ret, pos = 0xE8;
+
+    if (!(vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x201D) ||
+          vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x467F) ||
+          vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x4C3D) ||
+          vfio_pci_is(vdev, PCI_VENDOR_ID_INTEL, 0x9A0B))) {
+        return 0;
+    }
+
+    ret = pread(vdev->vbasedev.fd, membar_phys, 16,
+                vdev->config_offset + PCI_BASE_ADDRESS_2);
+    if (ret != 16) {
+        error_report("VMD %s cannot read MEMBARs (%d)",
+                     vdev->vbasedev.name, ret);
+        return -EFAULT;
+    }
+
+    ret = pci_add_capability(&vdev->pdev, PCI_CAP_ID_VNDR, pos,
+                             VMD_SHADOW_CAP_LEN, errp);
+    if (ret < 0) {
+        error_prepend(errp, "Failed to add VMD MEMBAR Shadow cap: ");
+        return ret;
+    }
+
+    memset(vdev->emulated_config_bits + pos, 0xFF, VMD_SHADOW_CAP_LEN);
+    pos += PCI_CAP_FLAGS;
+    pci_set_byte(vdev->pdev.config + pos++, VMD_SHADOW_CAP_LEN);
+    pci_set_byte(vdev->pdev.config + pos++, VMD_SHADOW_CAP_VER);
+    pci_set_long(vdev->pdev.config + pos, 0x53484457); /* SHDW */
+    memcpy(vdev->pdev.config + pos + 4, membar_phys, 16);
+
+    return 0;
+}
+
+int vfio_add_virt_caps(VFIOPCIDevice *vdev, Error **errp)
+{
+    int ret;
+
+    ret = vfio_add_nv_gpudirect_cap(vdev, errp);
+    if (ret) {
+        return ret;
+    }
+
+    ret = vfio_add_vmd_shadow_cap(vdev, errp);
+    if (ret) {
+        return ret;
+    }
+
+    return 0;
+}