aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAlex Williamson <alex.williamson@redhat.com>2013-12-06 11:16:23 -0700
committerAlex Williamson <alex.williamson@redhat.com>2013-12-06 11:16:23 -0700
commit96eeeba0db38b856eb2cae0e4a2a620d8d65771a (patch)
treec4e9f3db14104dd10a3a9f9342c4b55dbbbc9bd2
parent5b49ab188ff0339aa3097ce7f5309f1306092f9e (diff)
vfio-pci: Fix Nvidia MSI ACK through 0x88000 quirk
When MSI is enabled on Nvidia GeForce cards the driver seems to acknowledge the interrupt by writing a 0xff byte to the MSI capability ID register using the PCI config space mirror at offset 0x88000 from BAR0. Without this, the device will only fire a single interrupt. VFIO handles the PCI capability ID/next registers as virtual w/o write support, so any write through config space is currently dropped. Add a check for this and allow the write through the BAR window. The registers are read-only anyway. Signed-off-by: Alex Williamson <alex.williamson@redhat.com>
-rw-r--r--hw/misc/vfio.c30
1 files changed, 29 insertions, 1 deletions
diff --git a/hw/misc/vfio.c b/hw/misc/vfio.c
index f1aa4a7209..09bdddf18a 100644
--- a/hw/misc/vfio.c
+++ b/hw/misc/vfio.c
@@ -1811,6 +1811,34 @@ static void vfio_probe_nvidia_bar5_window_quirk(VFIODevice *vdev, int nr)
vdev->host.function);
}
+static void vfio_nvidia_88000_quirk_write(void *opaque, hwaddr addr,
+ uint64_t data, unsigned size)
+{
+ VFIOQuirk *quirk = opaque;
+ VFIODevice *vdev = quirk->vdev;
+ PCIDevice *pdev = &vdev->pdev;
+ hwaddr base = quirk->data.address_match & TARGET_PAGE_MASK;
+
+ vfio_generic_quirk_write(opaque, addr, data, size);
+
+ /*
+ * Nvidia seems to acknowledge MSI interrupts by writing 0xff to the
+ * MSI capability ID register. Both the ID and next register are
+ * read-only, so we allow writes covering either of those to real hw.
+ * NB - only fixed for the 0x88000 MMIO window.
+ */
+ if ((pdev->cap_present & QEMU_PCI_CAP_MSI) &&
+ vfio_range_contained(addr, size, pdev->msi_cap, PCI_MSI_FLAGS)) {
+ vfio_bar_write(&vdev->bars[quirk->data.bar], addr + base, data, size);
+ }
+}
+
+static const MemoryRegionOps vfio_nvidia_88000_quirk = {
+ .read = vfio_generic_quirk_read,
+ .write = vfio_nvidia_88000_quirk_write,
+ .endianness = DEVICE_LITTLE_ENDIAN,
+};
+
/*
* Finally, BAR0 itself. We want to redirect any accesses to either
* 0x1800 or 0x88000 through the PCI config space access functions.
@@ -1837,7 +1865,7 @@ static void vfio_probe_nvidia_bar0_88000_quirk(VFIODevice *vdev, int nr)
quirk->data.address_mask = PCIE_CONFIG_SPACE_SIZE - 1;
quirk->data.bar = nr;
- memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_generic_quirk,
+ memory_region_init_io(&quirk->mem, OBJECT(vdev), &vfio_nvidia_88000_quirk,
quirk, "vfio-nvidia-bar0-88000-quirk",
TARGET_PAGE_ALIGN(quirk->data.address_mask + 1));
memory_region_add_subregion_overlap(&vdev->bars[nr].mem,