@@ -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 = {};
@@ -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);
@@ -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.
@@ -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)