From patchwork Wed Jul 22 14:41:22 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Michael S. Tsirkin" X-Patchwork-Id: 36838 Received: from vger.kernel.org (vger.kernel.org [209.132.176.167]) by demeter.kernel.org (8.14.2/8.14.2) with ESMTP id n6MEgKdB006531 for ; Wed, 22 Jul 2009 14:42:20 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1751342AbZGVOmS (ORCPT ); Wed, 22 Jul 2009 10:42:18 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1751334AbZGVOmS (ORCPT ); Wed, 22 Jul 2009 10:42:18 -0400 Received: from mx2.redhat.com ([66.187.237.31]:56202 "EHLO mx2.redhat.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751210AbZGVOmR (ORCPT ); Wed, 22 Jul 2009 10:42:17 -0400 Received: from int-mx2.corp.redhat.com (int-mx2.corp.redhat.com [172.16.27.26]) by mx2.redhat.com (8.13.8/8.13.8) with ESMTP id n6MEgIPc012773 for ; Wed, 22 Jul 2009 10:42:18 -0400 Received: from ns3.rdu.redhat.com (ns3.rdu.redhat.com [10.11.255.199]) by int-mx2.corp.redhat.com (8.13.1/8.13.1) with ESMTP id n6MEgGHx028788; Wed, 22 Jul 2009 10:42:17 -0400 Received: from redhat.com (dhcp-0-94.tlv.redhat.com [10.35.0.94]) by ns3.rdu.redhat.com (8.13.8/8.13.8) with ESMTP id n6MEgFeg017859; Wed, 22 Jul 2009 10:42:15 -0400 Date: Wed, 22 Jul 2009 17:41:22 +0300 From: "Michael S. Tsirkin" To: kvm@vger.kernel.org, avi@redhat.com, gleb@redhat.com Subject: [PATCH 2/2] qemu-kvm: broken MSI routing work-around Message-ID: <20090722144122.GC7942@redhat.com> References: MIME-Version: 1.0 Content-Disposition: inline In-Reply-To: User-Agent: Mutt/1.5.19 (2009-01-05) X-Scanned-By: MIMEDefang 2.58 on 172.16.27.26 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org 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 --- 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;