mirror of https://lore.kernel.org/lkml/
 help / color / mirror / Atom feed
From: Avi Kivity <avi@redhat.com>
To: linux-kernel@vger.kernel.org
Cc: kvm@vger.kernel.org
Subject: [PATCH 10/43] KVM: Enable MSI-X for KVM assigned device
Date: Mon, 18 May 2009 12:22:32 +0300	[thread overview]
Message-ID: <1242638585-18470-11-git-send-email-avi@redhat.com> (raw)
In-Reply-To: <1242638585-18470-1-git-send-email-avi@redhat.com>

From: Sheng Yang <sheng@linux.intel.com>

This patch finally enable MSI-X.

What we need for MSI-X:
1. Intercept one page in MMIO region of device. So that we can get guest desired
MSI-X table and set up the real one. Now this have been done by guest, and
transfer to kernel using ioctl KVM_SET_MSIX_NR and KVM_SET_MSIX_ENTRY.

2. Information for incoming interrupt. Now one device can have more than one
interrupt, and they are all handled by one workqueue structure. So we need to
identify them. The previous patch enable gsi_msg_pending_bitmap get this done.

3. Mapping from host IRQ to guest gsi as well as guest gsi to real MSI/MSI-X
message address/data. We used same entry number for the host and guest here, so
that it's easy to find the correlated guest gsi.

What we lack for now:
1. The PCI spec said nothing can existed with MSI-X table in the same page of
MMIO region, except pending bits. The patch ignore pending bits as the first
step (so they are always 0 - no pending).

2. The PCI spec allowed to change MSI-X table dynamically. That means, the OS
can enable MSI-X, then mask one MSI-X entry, modify it, and unmask it. The patch
didn't support this, and Linux also don't work in this way.

3. The patch didn't implement MSI-X mask all and mask single entry. I would
implement the former in driver/pci/msi.c later. And for single entry, userspace
should have reposibility to handle it.

Signed-off-by: Sheng Yang <sheng@linux.intel.com>
Signed-off-by: Avi Kivity <avi@redhat.com>
---
 arch/x86/include/asm/kvm.h |    1 +
 include/linux/kvm.h        |    8 ++++
 virt/kvm/kvm_main.c        |   98 +++++++++++++++++++++++++++++++++++++++++---
 3 files changed, 101 insertions(+), 6 deletions(-)

diff --git a/arch/x86/include/asm/kvm.h b/arch/x86/include/asm/kvm.h
index dc3f6cf..125be8b 100644
--- a/arch/x86/include/asm/kvm.h
+++ b/arch/x86/include/asm/kvm.h
@@ -16,6 +16,7 @@
 #define __KVM_HAVE_MSI
 #define __KVM_HAVE_USER_NMI
 #define __KVM_HAVE_GUEST_DEBUG
+#define __KVM_HAVE_MSIX
 
 /* Architectural interrupt line count. */
 #define KVM_NR_INTERRUPTS 256
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 78cdee8..640835e 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -409,6 +409,9 @@ struct kvm_trace_rec {
 #ifdef __KVM_HAVE_DEVICE_ASSIGNMENT
 #define KVM_CAP_DEVICE_DEASSIGNMENT 27
 #endif
+#ifdef __KVM_HAVE_MSIX
+#define KVM_CAP_DEVICE_MSIX 28
+#endif
 /* Another bug in KVM_SET_USER_MEMORY_REGION fixed: */
 #define KVM_CAP_JOIN_MEMORY_REGIONS_WORKS 30
 
@@ -611,6 +614,11 @@ struct kvm_assigned_irq {
 #define KVM_DEV_IRQ_ASSIGN_MSI_ACTION	KVM_DEV_IRQ_ASSIGN_ENABLE_MSI
 #define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI	(1 << 0)
 
+#define KVM_DEV_IRQ_ASSIGN_MSIX_ACTION  (KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX |\
+					KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
+#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX  (1 << 1)
+#define KVM_DEV_IRQ_ASSIGN_MASK_MSIX    (1 << 2)
+
 struct kvm_assigned_msix_nr {
 	__u32 assigned_dev_id;
 	__u16 entry_nr;
diff --git a/virt/kvm/kvm_main.c b/virt/kvm/kvm_main.c
index 7c20e06..034ed43 100644
--- a/virt/kvm/kvm_main.c
+++ b/virt/kvm/kvm_main.c
@@ -236,13 +236,33 @@ static void kvm_free_assigned_irq(struct kvm *kvm,
 	 * now, the kvm state is still legal for probably we also have to wait
 	 * interrupt_work done.
 	 */
-	disable_irq_nosync(assigned_dev->host_irq);
-	cancel_work_sync(&assigned_dev->interrupt_work);
+	if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_MSIX) {
+		int i;
+		for (i = 0; i < assigned_dev->entries_nr; i++)
+			disable_irq_nosync(assigned_dev->
+					   host_msix_entries[i].vector);
+
+		cancel_work_sync(&assigned_dev->interrupt_work);
 
-	free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+		for (i = 0; i < assigned_dev->entries_nr; i++)
+			free_irq(assigned_dev->host_msix_entries[i].vector,
+				 (void *)assigned_dev);
 
-	if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI)
-		pci_disable_msi(assigned_dev->dev);
+		assigned_dev->entries_nr = 0;
+		kfree(assigned_dev->host_msix_entries);
+		kfree(assigned_dev->guest_msix_entries);
+		pci_disable_msix(assigned_dev->dev);
+	} else {
+		/* Deal with MSI and INTx */
+		disable_irq_nosync(assigned_dev->host_irq);
+		cancel_work_sync(&assigned_dev->interrupt_work);
+
+		free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+
+		if (assigned_dev->irq_requested_type &
+				KVM_ASSIGNED_DEV_HOST_MSI)
+			pci_disable_msi(assigned_dev->dev);
+	}
 
 	assigned_dev->irq_requested_type = 0;
 }
@@ -373,6 +393,60 @@ static int assigned_device_update_msi(struct kvm *kvm,
 }
 #endif
 
+#ifdef __KVM_HAVE_MSIX
+static int assigned_device_update_msix(struct kvm *kvm,
+			struct kvm_assigned_dev_kernel *adev,
+			struct kvm_assigned_irq *airq)
+{
+	/* TODO Deal with KVM_DEV_IRQ_ASSIGNED_MASK_MSIX */
+	int i, r;
+
+	adev->ack_notifier.gsi = -1;
+
+	if (irqchip_in_kernel(kvm)) {
+		if (airq->flags & KVM_DEV_IRQ_ASSIGN_MASK_MSIX)
+			return -ENOTTY;
+
+		if (!(airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX)) {
+			/* Guest disable MSI-X */
+			kvm_free_assigned_irq(kvm, adev);
+			if (msi2intx) {
+				pci_enable_msi(adev->dev);
+				if (adev->dev->msi_enabled)
+					return assigned_device_update_msi(kvm,
+							adev, airq);
+			}
+			return assigned_device_update_intx(kvm, adev, airq);
+		}
+
+		/* host_msix_entries and guest_msix_entries should have been
+		 * initialized */
+		if (adev->entries_nr == 0)
+			return -EINVAL;
+
+		kvm_free_assigned_irq(kvm, adev);
+
+		r = pci_enable_msix(adev->dev, adev->host_msix_entries,
+				    adev->entries_nr);
+		if (r)
+			return r;
+
+		for (i = 0; i < adev->entries_nr; i++) {
+			r = request_irq((adev->host_msix_entries + i)->vector,
+					kvm_assigned_dev_intr, 0,
+					"kvm_assigned_msix_device",
+					(void *)adev);
+			if (r)
+				return r;
+		}
+	}
+
+	adev->irq_requested_type |= KVM_ASSIGNED_DEV_MSIX;
+
+	return 0;
+}
+#endif
+
 static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 				   struct kvm_assigned_irq
 				   *assigned_irq)
@@ -417,12 +491,24 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 		}
 	}
 
-	if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
+	if (match->irq_requested_type & KVM_ASSIGNED_DEV_MSIX)
+		current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSIX;
+	else if ((match->irq_requested_type & KVM_ASSIGNED_DEV_HOST_MSI) &&
 		 (match->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI))
 		current_flags |= KVM_DEV_IRQ_ASSIGN_ENABLE_MSI;
 
 	changed_flags = assigned_irq->flags ^ current_flags;
 
+#ifdef __KVM_HAVE_MSIX
+	if (changed_flags & KVM_DEV_IRQ_ASSIGN_MSIX_ACTION) {
+		r = assigned_device_update_msix(kvm, match, assigned_irq);
+		if (r) {
+			printk(KERN_WARNING "kvm: failed to execute "
+					"MSI-X action!\n");
+			goto out_release;
+		}
+	} else
+#endif
 	if ((changed_flags & KVM_DEV_IRQ_ASSIGN_MSI_ACTION) ||
 	    (msi2intx && match->dev->msi_enabled)) {
 #ifdef CONFIG_X86
-- 
1.6.0.6


  parent reply	other threads:[~2009-05-18  9:33 UTC|newest]

Thread overview: 44+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2009-05-18  9:22 [PATCH 00/43] KVM updates for the 2.6.31 merge window (batch 1/4) Avi Kivity
2009-05-18  9:22 ` [PATCH 01/43] KVM: VMX: Don't use highmem pages for the msr and pio bitmaps Avi Kivity
2009-05-18  9:22 ` [PATCH 02/43] KVM: VMX: Don't intercept MSR_KERNEL_GS_BASE Avi Kivity
2009-05-18  9:22 ` [PATCH 03/43] KVM: Split IOAPIC structure Avi Kivity
2009-05-18  9:22 ` [PATCH 04/43] KVM: Unify the delivery of IOAPIC and MSI interrupts Avi Kivity
2009-05-18  9:22 ` [PATCH 05/43] KVM: Change API of kvm_ioapic_get_delivery_bitmask Avi Kivity
2009-05-18  9:22 ` [PATCH 06/43] KVM: Update intr delivery func to accept unsigned long* bitmap Avi Kivity
2009-05-18  9:22 ` [PATCH 07/43] KVM: bit ops for deliver_bitmap Avi Kivity
2009-05-18  9:22 ` [PATCH 08/43] KVM: Ioctls for init MSI-X entry Avi Kivity
2009-05-18  9:22 ` [PATCH 09/43] KVM: Add MSI-X interrupt injection logic Avi Kivity
2009-05-18  9:22 ` Avi Kivity [this message]
2009-05-18  9:22 ` [PATCH 11/43] KVM: x86: silence preempt warning on kvm_write_guest_time Avi Kivity
2009-05-18  9:22 ` [PATCH 12/43] KVM: x86: paravirt skip pit-through-ioapic boot check Avi Kivity
2009-05-18  9:22 ` [PATCH 13/43] KVM: declare ioapic functions only on affected hardware Avi Kivity
2009-05-18  9:22 ` [PATCH 14/43] KVM: PIT: remove unused scheduled variable Avi Kivity
2009-05-18  9:22 ` [PATCH 15/43] KVM: PIT: remove usage of count_load_time for channel 0 Avi Kivity
2009-05-18  9:22 ` [PATCH 16/43] KVM: unify part of generic timer handling Avi Kivity
2009-05-18  9:22 ` [PATCH 17/43] KVM: ia64: fix compilation error in kvm_get_lowest_prio_vcpu Avi Kivity
2009-05-18  9:22 ` [PATCH 18/43] KVM: Merge kvm_ioapic_get_delivery_bitmask into kvm_get_intr_delivery_bitmask Avi Kivity
2009-05-18  9:22 ` [PATCH 19/43] KVM: MMU: remove call to kvm_mmu_pte_write from walk_addr Avi Kivity
2009-05-18  9:22 ` [PATCH 20/43] KVM: APIC: kvm_apic_set_irq deliver all kinds of interrupts Avi Kivity
2009-05-18  9:22 ` [PATCH 21/43] KVM: ioapic/msi interrupt delivery consolidation Avi Kivity
2009-05-18  9:22 ` [PATCH 22/43] KVM: consolidate ioapic/ipi interrupt delivery logic Avi Kivity
2009-05-18  9:22 ` [PATCH 23/43] KVM: change the way how lowest priority vcpu is calculated Avi Kivity
2009-05-18  9:22 ` [PATCH 24/43] KVM: APIC: get rid of deliver_bitmask Avi Kivity
2009-05-18  9:22 ` [PATCH 25/43] KVM: ia64: Map in SN2 RTC registers to the VMM module Avi Kivity
2009-05-18  9:22 ` [PATCH 26/43] KVM: ia64: Create inline function kvm_get_itc() to centralize ITC reading Avi Kivity
2009-05-18  9:22 ` [PATCH 27/43] KVM: ia64: SN2 adjust emulated ITC frequency to match RTC frequency Avi Kivity
2009-05-18  9:22 ` [PATCH 28/43] KVM: ia64: Drop in SN2 replacement of fast path ITC emulation fault handler Avi Kivity
2009-05-18  9:22 ` [PATCH 29/43] KVM: make 'lapic_timer_ops' and 'kpit_ops' static Avi Kivity
2009-05-18  9:22 ` [PATCH 30/43] KVM: Device assignment framework rework Avi Kivity
2009-05-18  9:22 ` [PATCH 31/43] KVM: MMU: do not free active mmu pages in free_mmu_pages() Avi Kivity
2009-05-18  9:22 ` [PATCH 32/43] KVM: x86: Ignore reads to EVNTSEL MSRs Avi Kivity
2009-05-18  9:22 ` [PATCH 33/43] KVM: SVM: Remove duplicate code in svm_do_inject_vector() Avi Kivity
2009-05-18  9:22 ` [PATCH 34/43] KVM: reuse (pop|push)_irq from svm.c in vmx.c Avi Kivity
2009-05-18  9:22 ` [PATCH 35/43] KVM: VMX: Make module parameters readable Avi Kivity
2009-05-18  9:22 ` [PATCH 36/43] KVM: VMX: Rename kvm_handle_exit() to vmx_handle_exit() Avi Kivity
2009-05-18  9:22 ` [PATCH 37/43] KVM: VMX: Simplify module parameter names Avi Kivity
2009-05-18  9:23 ` [PATCH 38/43] KVM: VMX: Annotate module parameters as __read_mostly Avi Kivity
2009-05-18  9:23 ` [PATCH 39/43] KVM: VMX: Zero the vpid module parameter if vpid is not supported Avi Kivity
2009-05-18  9:23 ` [PATCH 40/43] KVM: VMX: Zero ept module parameter if ept is not present Avi Kivity
2009-05-18  9:23 ` [PATCH 41/43] KVM: VMX: Fold vm_need_ept() into callers Avi Kivity
2009-05-18  9:23 ` [PATCH 42/43] KVM: Timer event should not unconditionally unhalt vcpu Avi Kivity
2009-05-18  9:23 ` [PATCH 43/43] KVM: Fix interrupt unhalting a vcpu when it shouldn't Avi Kivity

Reply instructions:

You may reply publicly to this message via plain-text email
using any one of the following methods:

* Save the following mbox file, import it into your mail client,
  and reply-to-all from there: mbox

  Avoid top-posting and favor interleaved quoting:
  https://en.wikipedia.org/wiki/Posting_style#Interleaved_style

* Reply using the --to, --cc, and --in-reply-to
  switches of git-send-email(1):

  git send-email \
    --in-reply-to=1242638585-18470-11-git-send-email-avi@redhat.com \
    --to=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=linux-kernel@vger.kernel.org \
    /path/to/YOUR_REPLY

  https://kernel.org/pub/software/scm/git/docs/git-send-email.html

* If your mail client supports setting the In-Reply-To header
  via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox

all inboxes | Powered by JetHome®