Commit eea8f5df authored by Peter Maydell's avatar Peter Maydell
Browse files

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: default avatarPeter Maydell <peter.maydell@linaro.org>
parents 9f1f264e 643a4eac
Loading
Loading
Loading
Loading
+73 −12
Original line number Diff line number Diff line
@@ -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;
}