aboutsummaryrefslogtreecommitdiff
path: root/hw
diff options
context:
space:
mode:
authorPeter Maydell <peter.maydell@linaro.org>2020-06-11 22:36:28 +0100
committerPeter Maydell <peter.maydell@linaro.org>2020-06-11 22:36:28 +0100
commiteea8f5df4ecc607d64f091b8d916fcc11a697541 (patch)
tree4edb389f817421ee1a14ec6c298fca42afcd1b6e /hw
parent9f1f264edbdf5516d6f208497310b3eedbc7b74c (diff)
parent643a4eacef87a318cf71800a4fb2ae1f78c4b245 (diff)
Merge remote-tracking branch 'remotes/awilliam/tags/vfio-update-20200611.0' into staging
VFIO update 2020-06-11 - Fix IGD split, include header to honor Kconfig (Thomas Huth) - New VMD device paravirt quirk (Jon Derrick) # gpg: Signature made Thu 11 Jun 2020 19:58:31 BST # gpg: using RSA key 239B9B6E3BB08B22 # gpg: Good signature from "Alex Williamson <alex.williamson@redhat.com>" [full] # gpg: aka "Alex Williamson <alex@shazbot.org>" [full] # gpg: aka "Alex Williamson <alwillia@redhat.com>" [full] # gpg: aka "Alex Williamson <alex.l.williamson@gmail.com>" [full] # Primary key fingerprint: 42F6 C04E 540B D1A9 9E7B 8A90 239B 9B6E 3BB0 8B22 * remotes/awilliam/tags/vfio-update-20200611.0: hw/vfio/pci-quirks: Fix broken legacy IGD passthrough hw/vfio: Add VMD Passthrough Quirk Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'hw')
-rw-r--r--hw/vfio/pci-quirks.c85
1 files changed, 73 insertions, 12 deletions
diff --git a/hw/vfio/pci-quirks.c b/hw/vfio/pci-quirks.c
index f2155ddb1d..d304c81148 100644
--- a/hw/vfio/pci-quirks.c
+++ b/hw/vfio/pci-quirks.c
@@ -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"
@@ -1567,18 +1568,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 +1698,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;
+}