[PATCH 2/2] qemu-kvm: broken MSI routing work-around

[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

 



Kernels up to 2.6.31 have a bug: MSI entries where looked at when irq
is acked, address_lo was interpreted as irqchip, and
address_hi as pin.  If that matches a real interrupt this prevents
ack notifier from being processed.

Since these kernels ignore the value for address_hi when delivering
MSI, work around this by setting a value that never matches an
interrupt pin number.

Pointers to relevant kernel code, for reference: in kernel v2.6.31-rc3:
kvm_notify_acked_irq - fails to check irq type,
kvm_set_msi - ignored address_hi in message

Signed-off-by: Michael S. Tsirkin <mst@xxxxxxxxxx>
---
 qemu-kvm.c |   32 ++++++++++++++++++++++++++++++--
 1 files changed, 30 insertions(+), 2 deletions(-)

diff --git a/qemu-kvm.c b/qemu-kvm.c
index cebaa65..ec6d583 100644
--- a/qemu-kvm.c
+++ b/qemu-kvm.c
@@ -38,6 +38,32 @@
 #error libkvm: userspace and kernel version mismatch
 #endif
 
+#ifdef KVM_CAP_IRQ_ROUTING
+/* Broken MSI routing work-around:
+ * Kernels up to 2.6.31 have a bug: MSI entries where looked at when irq
+ * is acked, address_lo was interpreted as irqchip, and
+ * address_hi as pin.  If that matches a real interrupt this prevents
+ * ack notifier from being processed.
+ *
+ * Since these kernels ignore the value for address_hi when delivering
+ * MSI, work around this by setting a value that never matches an
+ * interrupt pin number.
+ */
+#define KVM_BROKEN_MSI_ROUTING 1
+static inline
+void kvm_broken_msi_fix(struct kvm_irq_routing_entry *entry)
+{
+	if (entry->type == KVM_IRQ_ROUTING_MSI) {
+		entry->u.msi.address_hi = 0xffffffff;
+	}
+}
+static inline
+unsigned kvm_broken_msi_address_hi(struct kvm_irq_routing_entry *entry)
+{
+	return 0xffffffff;
+}
+#endif
+
 int kvm_allowed = 1;
 int kvm_irqchip = 1;
 int kvm_pit = 1;
@@ -1433,6 +1459,7 @@ int kvm_add_routing_entry(kvm_context_t kvm,
 	new->type = entry->type;
 	new->flags = entry->flags;
 	new->u = entry->u;
+	kvm_broken_msi_fix(new);
 
 	set_gsi(kvm, entry->gsi);
 
@@ -1489,7 +1516,7 @@ int kvm_del_routing_entry(kvm_context_t kvm,
 				if (e->u.msi.address_lo ==
 				    entry->u.msi.address_lo
 				    && e->u.msi.address_hi ==
-				    entry->u.msi.address_hi
+				    kvm_broken_msi_address_hi(entry)
 				    && e->u.msi.data == entry->u.msi.data) {
 					p = &kvm->irq_routes->
 					    entries[--kvm->irq_routes->nr];
@@ -1550,9 +1577,10 @@ int kvm_update_routing_entry(kvm_context_t kvm,
             break;
         case KVM_IRQ_ROUTING_MSI:
             if (e->u.msi.address_lo == entry->u.msi.address_lo &&
-                e->u.msi.address_hi == entry->u.msi.address_hi &&
+                e->u.msi.address_hi == kvm_broken_msi_address_hi(entry) &&
                 e->u.msi.data == entry->u.msi.data) {
                 memcpy(&e->u.msi, &newentry->u.msi, sizeof e->u.msi);
+		kvm_broken_msi_fix(e);
                 return 0;
             }
             break;
-- 
1.6.2.5
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to majordomo@xxxxxxxxxxxxxxx
More majordomo info at  http://vger.kernel.org/majordomo-info.html

[Index of Archives]     [KVM ARM]     [KVM ia64]     [KVM ppc]     [Virtualization Tools]     [Spice Development]     [Libvirt]     [Libvirt Users]     [Linux USB Devel]     [Linux Audio Users]     [Yosemite Questions]     [Linux Kernel]     [Linux SCSI]     [XFree86]
  Powered by Linux