From: Xiang Chen <chenxiang66@hisilicon.com>
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@hisilicon.com>
---
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