From mboxrd@z Thu Jan 1 00:00:00 1970 From: Sheng Yang Subject: [PATCH 14/15] KVM: Using kfifo for irq recording Date: Thu, 25 Dec 2008 17:09:38 +0800 Message-ID: <1230196179-6918-15-git-send-email-sheng@linux.intel.com> References: <1230196179-6918-1-git-send-email-sheng@linux.intel.com> Cc: kvm@vger.kernel.org, Sheng Yang To: Avi Kivity , Marcelo Tosatti Return-path: Received: from mga01.intel.com ([192.55.52.88]:6835 "EHLO mga01.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751580AbYLYJJo (ORCPT ); Thu, 25 Dec 2008 04:09:44 -0500 In-Reply-To: <1230196179-6918-1-git-send-email-sheng@linux.intel.com> Sender: kvm-owner@vger.kernel.org List-ID: For MSI-X, we have to deal with multiply IRQ with same IRQ handler, so it's necessary to record the IRQ that trigger the IRQ handler. And this one is also useful for fixing kvm_free_assigned_irq(). Signed-off-by: Sheng Yang --- include/linux/kvm_host.h | 4 ++++ virt/kvm/kvm_main.c | 30 +++++++++++++++++++++++++++--- 2 files changed, 31 insertions(+), 3 deletions(-) diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h index fbf102c..84b11d5 100644 --- a/include/linux/kvm_host.h +++ b/include/linux/kvm_host.h @@ -17,6 +17,7 @@ #include #include #include +#include #include #include @@ -313,6 +314,9 @@ struct kvm_assigned_dev_kernel { int host_irq; bool host_irq_disabled; int guest_irq; +#define KVM_ASSIGNED_DEV_IRQ_FIFO_LEN 0x100 + struct kfifo *irq_fifo; + spinlock_t irq_fifo_lock; #define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0) #define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1) #define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8) diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c index a51e630..1863942 100644 --- a/virt/kvm/kvm_main.c +++ b/virt/kvm/kvm_main.c @@ -99,6 +99,8 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) { struct kvm_assigned_dev_kernel *assigned_dev; + int irq; + u32 gsi; assigned_dev = container_of(work, struct kvm_assigned_dev_kernel, interrupt_work); @@ -109,14 +111,22 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work) */ mutex_lock(&assigned_dev->kvm->lock); - kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id, - assigned_dev->guest_irq, 1); +handle_irq: + kfifo_get(assigned_dev->irq_fifo, + (unsigned char *)&irq, sizeof(int)); + + 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; } + if (kfifo_len(assigned_dev->irq_fifo) != 0) + goto handle_irq; + mutex_unlock(&assigned_dev->kvm->lock); kvm_put_kvm(assigned_dev->kvm); } @@ -128,6 +138,9 @@ static irqreturn_t kvm_assigned_dev_intr(int irq, void *dev_id) kvm_get_kvm(assigned_dev->kvm); + kfifo_put(assigned_dev->irq_fifo, + (unsigned char *)&irq, sizeof(int)); + schedule_work(&assigned_dev->interrupt_work); disable_irq_nosync(irq); @@ -201,6 +214,7 @@ static void kvm_free_assigned_device(struct kvm *kvm, pci_dev_put(assigned_dev->dev); list_del(&assigned_dev->list); + kfifo_free(assigned_dev->irq_fifo); kfree(assigned_dev); } @@ -448,15 +462,25 @@ static int kvm_vm_ioctl_assign_device(struct kvm *kvm, list_add(&match->list, &kvm->arch.assigned_dev_head); + spin_lock_init(&match->irq_fifo_lock); + match->irq_fifo = kfifo_alloc(sizeof(unsigned char) * + KVM_ASSIGNED_DEV_IRQ_FIFO_LEN, + GFP_KERNEL | __GFP_ZERO, + &match->irq_fifo_lock); + if (!match->irq_fifo) + goto out_list_del; + if (assigned_dev->flags & KVM_DEV_ASSIGN_ENABLE_IOMMU) { r = kvm_iommu_map_guest(kvm, match); if (r) - goto out_list_del; + goto out_fifo_del; } out: mutex_unlock(&kvm->lock); return r; +out_fifo_del: + kfifo_free(match->irq_fifo); out_list_del: list_del(&match->list); pci_release_regions(dev); -- 1.5.4.5