static int vfio_msix_vector_do_use(PCIDevice *pdev, unsigned int nr, MSIMessage *msg, IOHandler *handler) { VFIOPCIDevice *vdev = DO_UPCAST(VFIOPCIDevice, pdev, pdev); VFIOMSIVector *vector; int ret; trace_vfio_msix_vector_do_use(vdev->vbasedev.name, nr); vector = &vdev->msi_vectors[nr]; if (!vector->use) { vector->vdev = vdev; vector->virq = -1; if (event_notifier_init(&vector->interrupt, 0)) { error_report("vfio: Error: event_notifier_init failed"); } vector->use = true; msix_vector_use(pdev, nr); } qemu_set_fd_handler(event_notifier_get_fd(&vector->interrupt), handler, NULL, vector); /* * Attempt to enable route through KVM irqchip, * default to userspace handling if unavailable. */ if (vector->virq >= 0) { if (!msg) { vfio_remove_kvm_msi_virq(vector); } else { vfio_update_kvm_msi_virq(vector, *msg, pdev); } } else { vfio_add_kvm_msi_virq(vdev, vector, nr, true); } /* * We don't want to have the host allocate all possible MSI vectors * for a device if they're not in use, so we shutdown and incrementally * increase them as needed. */ if (vdev->nr_vectors < nr + 1) { vfio_disable_irqindex(&vdev->vbasedev, VFIO_PCI_MSIX_IRQ_INDEX); vdev->nr_vectors = nr + 1; ret = vfio_enable_vectors(vdev, true); if (ret) { error_report("vfio: failed to enable vectors, %d", ret); } } else { int argsz; struct vfio_irq_set *irq_set; int32_t *pfd; argsz = sizeof(*irq_set) + sizeof(*pfd); irq_set = g_malloc0(argsz); irq_set->argsz = argsz; irq_set->flags = VFIO_IRQ_SET_DATA_EVENTFD | VFIO_IRQ_SET_ACTION_TRIGGER; irq_set->index = VFIO_PCI_MSIX_IRQ_INDEX; irq_set->start = nr; irq_set->count = 1; pfd = (int32_t *)&irq_set->data; if (vector->virq >= 0) { *pfd = event_notifier_get_fd(&vector->kvm_interrupt); } else { *pfd = event_notifier_get_fd(&vector->interrupt); } ret = ioctl(vdev->vbasedev.fd, VFIO_DEVICE_SET_IRQS, irq_set); g_free(irq_set); if (ret) { error_report("vfio: failed to modify vector, %d", ret); } } /* Disable PBA emulation when nothing more is pending. */ clear_bit(nr, vdev->msix->pending); if (find_first_bit(vdev->msix->pending, vdev->nr_vectors) == vdev->nr_vectors) { memory_region_set_enabled(&vdev->pdev.msix_pba_mmio, false); trace_vfio_msix_pba_disable(vdev->vbasedev.name); } return 0; }