From: Xiang Chen <chenxiang66@xxxxxxxxxxxxx> Currently the numbers of MSI vectors come from register PCI_MSI_FLAGS which should be power-of-2, but in some scenaries it is not the same as the number that driver requires in guest, for example, a PCI driver wants to allocate 6 MSI vecotrs in guest, but as the limitation, it will allocate 8 MSI vectors. So it requires 8 MSI vectors in qemu while the driver in guest only wants to allocate 6 MSI vectors. When GICv4.1 is enabled, we can see some exception print as following for above scenaro: vfio-pci 0000:3a:00.1: irq bypass producer (token 000000008f08224d) registration fails:66311 To avoid the issue, add system call KVM_VERIFY_MSI to verify whether every MSI vecotor is valid and adjust the numver of MSI vectors. This is qemu part of adding system call KVM_VERIFY_MSI. Signed-off-by: Xiang Chen <chenxiang66@xxxxxxxxxxxxx> --- accel/kvm/kvm-all.c | 19 +++++++++++++++++++ hw/vfio/pci.c | 13 +++++++++++++ include/sysemu/kvm.h | 2 ++ linux-headers/linux/kvm.h | 1 + 4 files changed, 35 insertions(+) diff --git a/accel/kvm/kvm-all.c b/accel/kvm/kvm-all.c index f99b0be..19c8b84 100644 --- a/accel/kvm/kvm-all.c +++ b/accel/kvm/kvm-all.c @@ -1918,6 +1918,25 @@ int kvm_irqchip_send_msi(KVMState *s, MSIMessage msg) return kvm_set_irq(s, route->kroute.gsi, 1); } +int kvm_irqchip_verify_msi_route(KVMState *s, int vector, PCIDevice *dev) +{ + if (pci_available && dev && kvm_msi_devid_required()) { + MSIMessage msg = {0, 0}; + struct kvm_msi msi; + + msg = pci_get_msi_message(dev, vector); + msi.address_lo = (uint32_t)msg.address; + msi.address_hi = msg.address >> 32; + msi.devid = pci_requester_id(dev); + msi.data = le32_to_cpu(msg.data); + msi.flags = KVM_MSI_VALID_DEVID; + memset(msi.pad, 0, sizeof(msi.pad)); + + return kvm_vm_ioctl(s, KVM_VERIFY_MSI, &msi); + } + return 0; +} + int kvm_irqchip_add_msi_route(KVMRouteChange *c, int vector, PCIDevice *dev) { struct kvm_irq_routing_entry kroute = {}; diff --git a/hw/vfio/pci.c b/hw/vfio/pci.c index 939dcc3..8dae0e4 100644 --- a/hw/vfio/pci.c +++ b/hw/vfio/pci.c @@ -660,6 +660,7 @@ static void vfio_msix_enable(VFIOPCIDevice *vdev) static void vfio_msi_enable(VFIOPCIDevice *vdev) { int ret, i; + int msi_invalid = 0; vfio_disable_interrupts(vdev); @@ -671,6 +672,18 @@ static void vfio_msi_enable(VFIOPCIDevice *vdev) vfio_prepare_kvm_msi_virq_batch(vdev); vdev->nr_vectors = msi_nr_vectors_allocated(&vdev->pdev); + + /* + * Verify whether every msi interrupt is valid as the number of + * MSI vectors comes from PCI device registers which may be not the + * same as the number of vectors that driver requires. + */ + for (i = 0; i < vdev->nr_vectors; i++) { + ret = kvm_irqchip_verify_msi_route(kvm_state, i, &vdev->pdev); + if (ret < 0) + msi_invalid++; + } + vdev->nr_vectors -= msi_invalid; retry: vdev->msi_vectors = g_new0(VFIOMSIVector, vdev->nr_vectors); diff --git a/include/sysemu/kvm.h b/include/sysemu/kvm.h index e9a97ed..aca6e5b 100644 --- a/include/sysemu/kvm.h +++ b/include/sysemu/kvm.h @@ -482,6 +482,8 @@ void kvm_cpu_synchronize_state(CPUState *cpu); void kvm_init_cpu_signals(CPUState *cpu); +int kvm_irqchip_verify_msi_route(KVMState *s, int vector, PCIDevice *dev); + /** * kvm_irqchip_add_msi_route - Add MSI route for specific vector * @c: KVMRouteChange instance. diff --git a/linux-headers/linux/kvm.h b/linux-headers/linux/kvm.h index ebdafa5..ac59350 100644 --- a/linux-headers/linux/kvm.h +++ b/linux-headers/linux/kvm.h @@ -1540,6 +1540,7 @@ struct kvm_s390_ucas_mapping { #define KVM_PPC_SVM_OFF _IO(KVMIO, 0xb3) #define KVM_ARM_MTE_COPY_TAGS _IOR(KVMIO, 0xb4, struct kvm_arm_copy_mte_tags) +#define KVM_VERIFY_MSI _IOW(KVMIO, 0xb5, struct kvm_msi) /* ioctl for vm fd */ #define KVM_CREATE_DEVICE _IOWR(KVMIO, 0xe0, struct kvm_create_device) -- 2.8.1