Add the -d option to vfio_pci_device_irq_test that will make the device send an MSI rather than synthesizing an eventfd notification from VFIO. This requires a VFIO selftest driver for the device that supports the send_msi() function.
This option allows the test to exercise IRQ Bypass (e.g. VT-d device-posted interrupts in Intel).
Signed-off-by: David Matlack dmatlack@google.com --- .../selftests/kvm/vfio_pci_device_irq_test.c | 61 +++++++++++++++++-- 1 file changed, 55 insertions(+), 6 deletions(-)
diff --git a/tools/testing/selftests/kvm/vfio_pci_device_irq_test.c b/tools/testing/selftests/kvm/vfio_pci_device_irq_test.c index 9b90cf9dd38f..64fd4efe2096 100644 --- a/tools/testing/selftests/kvm/vfio_pci_device_irq_test.c +++ b/tools/testing/selftests/kvm/vfio_pci_device_irq_test.c @@ -7,6 +7,8 @@ #include <pthread.h> #include <time.h> #include <linux/vfio.h> +#include <linux/sizes.h> + #include <vfio_util.h>
static bool guest_ready_for_irq; @@ -60,10 +62,53 @@ void *vcpu_thread_main(void *arg)
static void help(const char *name) { - printf("Usage: %s [-i iommu_mode] [segment:bus:device.function]\n", name); + printf("Usage: %s [-i iommu_mode] [-d] [segment:bus:device.function]\n", name); + printf(" -d: Send a real MSI from the device, rather than synthesizing\n" + " an eventfd signal from VFIO. Note that this option requires\n" + " a VFIO selftests driver that supports the device.\n"); exit(KSFT_FAIL); }
+static int setup_msi(struct vfio_pci_device *device, bool use_device_msi) +{ + const int flags = MAP_SHARED | MAP_ANONYMOUS; + const int prot = PROT_READ | PROT_WRITE; + struct vfio_dma_region *region; + + if (use_device_msi) { + /* A driver is required to generate an MSI. */ + TEST_REQUIRE(device->driver.ops); + + /* Set up a DMA-able region for the driver to use. */ + region = &device->driver.region; + region->iova = 0; + region->size = SZ_2M; + region->vaddr = mmap(NULL, region->size, prot, flags, -1, 0); + TEST_ASSERT(region->vaddr != MAP_FAILED, "mmap() failed\n"); + vfio_pci_dma_map(device, region); + + vfio_pci_driver_init(device); + + return device->driver.msi; + } + + TEST_REQUIRE(device->msix_info.count > 0); + vfio_pci_msix_enable(device, 0, 1); + return 0; +} + +static void send_msi(struct vfio_pci_device *device, bool use_device_msi, int msi) +{ + if (use_device_msi) { + printf("Sending MSI %d from the device\n", msi); + TEST_ASSERT_EQ(msi, device->driver.msi); + vfio_pci_driver_send_msi(device); + } else { + printf("Notifying the eventfd for MSI %d from VFIO\n", msi); + vfio_pci_irq_trigger(device, VFIO_PCI_MSIX_IRQ_INDEX, msi); + } +} + int main(int argc, char **argv) { /* Random non-reserved vector and GSI to use for the device IRQ */ @@ -73,19 +118,24 @@ int main(int argc, char **argv) struct timespec start, elapsed; struct vfio_pci_device *device; const char *iommu_mode = NULL; + bool use_device_msi = false; const char *device_bdf; struct kvm_vcpu *vcpu; pthread_t vcpu_thread; struct kvm_vm *vm; + int msi; int c;
device_bdf = vfio_selftests_get_bdf(&argc, argv);
- while ((c = getopt(argc, argv, "i:")) != -1) { + while ((c = getopt(argc, argv, "i:d")) != -1) { switch (c) { case 'i': iommu_mode = optarg; break; + case 'd': + use_device_msi = true; + break; default: help(argv[0]); } @@ -95,10 +145,9 @@ int main(int argc, char **argv) vm_install_exception_handler(vm, vector, guest_irq_handler);
device = vfio_pci_device_init(device_bdf, iommu_mode); - TEST_REQUIRE(device->msix_info.count > 0); + msi = setup_msi(device, use_device_msi);
- vfio_pci_msix_enable(device, 0, 1); - kvm_add_irqfd(vm, gsi, device->msi_eventfds[0]); + kvm_add_irqfd(vm, gsi, device->msi_eventfds[msi]); kvm_route_msi(vm, gsi, vcpu, vector);
pthread_create(&vcpu_thread, NULL, vcpu_thread_main, vcpu); @@ -106,7 +155,7 @@ int main(int argc, char **argv) while (!READ_ONCE(guest_ready_for_irq)) sync_global_from_guest(vm, guest_ready_for_irq);
- vfio_pci_irq_trigger(device, VFIO_PCI_MSIX_IRQ_INDEX, 0); + send_msi(device, use_device_msi, msi);
clock_gettime(CLOCK_MONOTONIC, &start);