From patchwork Wed Feb 11 08:08:50 2009 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Sheng Yang X-Patchwork-Id: 6627 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 n1B89EYl014045 for ; Wed, 11 Feb 2009 08:09:14 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752635AbZBKII4 (ORCPT ); Wed, 11 Feb 2009 03:08:56 -0500 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1752728AbZBKII4 (ORCPT ); Wed, 11 Feb 2009 03:08:56 -0500 Received: from mga11.intel.com ([192.55.52.93]:1130 "EHLO mga11.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752635AbZBKIIz (ORCPT ); Wed, 11 Feb 2009 03:08:55 -0500 Received: from fmsmga001.fm.intel.com ([10.253.24.23]) by fmsmga102.fm.intel.com with ESMTP; 11 Feb 2009 00:07:34 -0800 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="4.38,191,1233561600"; d="scan'208";a="664648679" Received: from syang10-desktop.sh.intel.com (HELO syang10-desktop) ([10.239.13.102]) by fmsmga001.fm.intel.com with ESMTP; 11 Feb 2009 00:12:49 -0800 Received: from yasker by syang10-desktop with local (Exim 4.69) (envelope-from ) id 1LXA9L-0000py-TN; Wed, 11 Feb 2009 16:08:51 +0800 From: Sheng Yang To: Avi Kivity Cc: kvm@vger.kernel.org, Sheng Yang Subject: [PATCH 2/3] KVM: Add gsi_msg_pending_bitmap for MSI-X Date: Wed, 11 Feb 2009 16:08:50 +0800 Message-Id: <1234339731-3195-3-git-send-email-sheng@linux.intel.com> X-Mailer: git-send-email 1.5.6.3 In-Reply-To: <1234339731-3195-1-git-send-email-sheng@linux.intel.com> References: <1234339731-3195-1-git-send-email-sheng@linux.intel.com> Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org We have to handle more than one interrupt with one handler for MSI-X. So we need a bitmap to track the triggered interrupts. Signed-off-by: Sheng Yang --- include/linux/kvm_host.h | 5 +- virt/kvm/kvm_main.c | 103 ++++++++++++++++++++++++++++++++++++++++++++- 2 files changed, 103 insertions(+), 5 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index a7d6123..c081867 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -144,6 +144,8 @@ struct kvm { #ifdef CONFIG_HAVE_KVM_IRQCHIP struct list_head irq_routing; /* of kvm_kernel_irq_routing_entry */ struct hlist_head mask_notifier_list; +#define KVM_MAX_IRQ_ROUTES 1024 + DECLARE_BITMAP(irq_routes_pending_bitmap, KVM_MAX_IRQ_ROUTES); #endif #ifdef KVM_ARCH_WANT_MMU_NOTIFIER @@ -335,6 +337,7 @@ struct kvm_assigned_dev_kernel { #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) #define KVM_ASSIGNED_DEV_HOST_MSI (1 << 9) +#define KVM_ASSIGNED_DEV_MSIX ((1 << 2) | (1 << 10)) unsigned long irq_requested_type; int irq_source_id; int flags; @@ -502,8 +505,6 @@ static inline int mmu_notifier_retry(struct kvm_vcpu *vcpu, unsigned long mmu_se #ifdef CONFIG_HAVE_KVM_IRQCHIP -#define KVM_MAX_IRQ_ROUTES 1024 - int kvm_setup_default_irq_routing(struct kvm *kvm); int kvm_set_irq_routing(struct kvm *kvm, const struct kvm_irq_routing_entry *entries, diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index ea96690..961603f 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -95,25 +95,113 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h return NULL; } +static int find_host_irq_from_gsi(struct kvm_assigned_dev_kernel *assigned_dev, + u32 gsi) +{ + int i, entry, irq; + struct msix_entry *host_msix_entries, *guest_msix_entries; + + host_msix_entries = assigned_dev->host_msix_entries; + guest_msix_entries = assigned_dev->guest_msix_entries; + + entry = -1; + irq = 0; + for (i = 0; i < assigned_dev->entries_nr; i++) + if (gsi == (guest_msix_entries + i)->vector) { + entry = (guest_msix_entries + i)->entry; + break; + } + if (entry < 0) { + printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n"); + return 0; + } + for (i = 0; i < assigned_dev->entries_nr; i++) + if (entry == (host_msix_entries + i)->entry) { + irq = (host_msix_entries + i)->vector; + break; + } + if (irq == 0) { + printk(KERN_WARNING "Fail to find correlated MSI-X irq!\n"); + return 0; + } + + return irq; +} + +static u32 find_gsi_from_host_irq(struct kvm_assigned_dev_kernel *assigned_dev, + int irq) +{ + int i, entry; + u32 gsi; + struct msix_entry *host_msix_entries, *guest_msix_entries; + + host_msix_entries = assigned_dev->host_msix_entries; + guest_msix_entries = assigned_dev->guest_msix_entries; + + entry = -1; + gsi = 0; + for (i = 0; i < assigned_dev->entries_nr; i++) + if (irq == (host_msix_entries + i)->vector) { + entry = (host_msix_entries + i)->entry; + break; + } + if (entry < 0) { + printk(KERN_WARNING "Fail to find correlated MSI-X entry!\n"); + return 0; + } + for (i = 0; i < assigned_dev->entries_nr; i++) + if (entry == (guest_msix_entries + i)->entry) { + gsi = (guest_msix_entries + i)->vector; + break; + } + if (gsi == 0) { + printk(KERN_WARNING "Fail to find correlated MSI-X gsi!\n"); + return 0; + } + + return gsi; +} + static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) { struct kvm_assigned_dev_kernel *assigned_dev; + struct kvm *kvm; + u32 gsi; + int irq; assigned_dev = container_of(work, struct kvm_assigned_dev_kernel, interrupt_work); + kvm = assigned_dev->kvm; /* This is taken to safely inject irq inside the guest. When * the interrupt injection (or the ioapic code) uses a * finer-grained lock, update this */ - mutex_lock(&assigned_dev->kvm->lock); - kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, - assigned_dev->guest_irq, 1); + mutex_lock(&kvm->lock); +handle_irq: + if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) { + gsi = find_first_bit(kvm->irq_routes_pending_bitmap, + KVM_MAX_IRQ_ROUTES); + BUG_ON(gsi >= KVM_MAX_IRQ_ROUTES); + clear_bit(gsi, kvm->irq_routes_pending_bitmap); + } else + gsi = assigned_dev->guest_irq; + + kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, gsi, 1); if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) { enable_irq(assigned_dev->host_irq); assigned_dev->host_irq_disabled = false; + } else if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) { + irq = find_host_irq_from_gsi(assigned_dev, gsi); + enable_irq(irq); + assigned_dev->host_irq_disabled = false; + gsi = find_first_bit(kvm->irq_routes_pending_bitmap, + KVM_MAX_IRQ_ROUTES); + if (gsi < KVM_MAX_IRQ_ROUTES) + goto handle_irq; } + mutex_unlock(&assigned_dev->kvm->lock); } @@ -121,6 +209,15 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) { struct kvm_assigned_dev_kernel *assigned_dev = (struct kvm_assigned_dev_kernel *) dev_id; + struct kvm *kvm = assigned_dev->kvm; + + if (assigned_dev->irq_requested_type == KVM_ASSIGNED_DEV_MSIX) { + u32 gsi; + gsi = find_gsi_from_host_irq(assigned_dev, irq); + if (gsi == 0) + return IRQ_HANDLED; + set_bit(gsi, kvm->irq_routes_pending_bitmap); + } schedule_work(&assigned_dev->interrupt_work);