All of lore.kernel.org
 help / color / mirror / Atom feed
From: Sheng Yang <sheng@linux.intel.com>
To: Avi Kivity <avi@redhat.com>
Cc: kvm@vger.kernel.org, Sheng Yang <sheng@linux.intel.com>
Subject: [PATCH 4/4] KVM: Enable MSI for device assignment
Date: Wed,  8 Oct 2008 16:38:13 +0800	[thread overview]
Message-ID: <1223455093-304-5-git-send-email-sheng@linux.intel.com> (raw)
In-Reply-To: <1223455093-304-1-git-send-email-sheng@linux.intel.com>


Signed-off-by: Sheng Yang <sheng@linux.intel.com>
---
 arch/x86/kvm/x86.c       |  115 ++++++++++++++++++++++++++++++++++++++++++++--
 include/linux/kvm.h      |    4 ++
 include/linux/kvm_host.h |    3 +
 virt/kvm/ioapic.c        |    2 +-
 virt/kvm/ioapic.h        |    2 +
 5 files changed, 120 insertions(+), 6 deletions(-)

diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 19688b3..a4bedf5 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -41,6 +41,7 @@
 #include <asm/msr.h>
 #include <asm/desc.h>
 #include <asm/mtrr.h>
+#include <asm/msidef.h>
 
 #define MAX_IO_MSRS 256
 #define CR0_RESERVED_BITS						\
@@ -121,6 +122,50 @@ static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *h
 	return NULL;
 }
 
+static void assigned_device_msi_dispatch(struct kvm_assigned_dev_kernel
+							*assigned_dev)
+{
+	u8 dest_id = assigned_dev->guest_msi_addr & MSI_ADDR_DEST_ID_MASK;
+	u8 vector = assigned_dev->guest_msi_data & MSI_DATA_VECTOR_MASK;
+	u8 dest_mode = assigned_dev->guest_msi_addr &
+					(1 << MSI_ADDR_DEST_MODE_SHIFT);
+	u8 trig_mode = assigned_dev->guest_msi_data &
+					(1 << MSI_DATA_TRIGGER_SHIFT);
+	u8 delivery_mode = assigned_dev->guest_msi_data &
+					MSI_DATA_DELIVERY_MODE_MASK;
+	u32 deliver_bitmask;
+	int vcpu_id;
+	struct kvm_vcpu *vcpu;
+	struct kvm_ioapic *ioapic = ioapic_irqchip(assigned_dev->kvm);
+
+	BUG_ON(!ioapic);
+
+	deliver_bitmask = ioapic_get_delivery_bitmask(ioapic,
+						      dest_id, dest_mode);
+	switch (delivery_mode) {
+	case MSI_DATA_DELIVERY_LOWPRI_VAL:
+		vcpu = kvm_get_lowest_prio_vcpu(ioapic->kvm, vector,
+				deliver_bitmask);
+		if (vcpu != NULL)
+			kvm_apic_set_irq(vcpu, vector, trig_mode);
+		else
+			printk(KERN_INFO "Null lowest priority vcpu!\n");
+		break;
+	case MSI_DATA_DELIVERY_FIXED_VAL:
+		for (vcpu_id = 0; deliver_bitmask != 0; vcpu_id++) {
+			if (!(deliver_bitmask & (1 << vcpu_id)))
+				continue;
+			deliver_bitmask &= ~(1 << vcpu_id);
+			vcpu = ioapic->kvm->vcpus[vcpu_id];
+			if (vcpu)
+				kvm_apic_set_irq(vcpu, vector, trig_mode);
+		}
+		break;
+	default:
+		printk(KERN_INFO "Unsupported MSI delivery mode\n");
+	}
+}
+
 static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
 {
 	struct kvm_assigned_dev_kernel *assigned_dev;
@@ -133,8 +178,12 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
 	 * finer-grained lock, update this
 	 */
 	mutex_lock(&assigned_dev->kvm->lock);
-	kvm_set_irq(assigned_dev->kvm,
-		    assigned_dev->guest_irq, 1);
+	if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_INTR)
+		kvm_set_irq(assigned_dev->kvm, assigned_dev->guest_irq, 1);
+	else if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_MSI) {
+		assigned_device_msi_dispatch(assigned_dev);
+		enable_irq(assigned_dev->host_irq);
+	}
 	mutex_unlock(&assigned_dev->kvm->lock);
 	kvm_put_kvm(assigned_dev->kvm);
 }
@@ -173,6 +222,8 @@ static void kvm_free_assigned_device(struct kvm *kvm,
 {
 	if (irqchip_in_kernel(kvm) && assigned_dev->guest_intr_type)
 		free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+	if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_MSI)
+		pci_disable_msi(assigned_dev->dev);
 
 	kvm_unregister_irq_ack_notifier(kvm, &assigned_dev->ack_notifier);
 
@@ -216,6 +267,11 @@ static int assigned_device_update_irq(struct kvm *kvm,
 		return 0;
 	}
 	if (irqchip_in_kernel(kvm)) {
+		if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_MSI) {
+			free_irq(assigned_dev->host_irq, (void *)kvm);
+			pci_disable_msi(assigned_dev->dev);
+		}
+
 		if (!capable(CAP_SYS_RAWIO))
 			return -EPERM;
 
@@ -240,6 +296,40 @@ static int assigned_device_update_irq(struct kvm *kvm,
 	return 0;
 }
 
+static int assigned_device_update_msi(struct kvm *kvm,
+			struct kvm_assigned_dev_kernel *assigned_dev,
+			struct kvm_assigned_irq *assigned_irq)
+{
+	int r;
+
+	if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_MSI)
+		return 0;
+
+	if (irqchip_in_kernel(kvm)) {
+		if (assigned_dev->guest_intr_type == KVM_ASSIGNED_DEV_INTR)
+			free_irq(assigned_dev->host_irq, (void *)assigned_dev);
+
+		assigned_dev->guest_msi_addr = assigned_irq->guest_msi_addr;
+		assigned_dev->guest_msi_data = assigned_irq->guest_msi_data;
+
+		r = pci_enable_msi(assigned_dev->dev);
+		if (r)
+			return r;
+
+		if (request_irq(assigned_dev->dev->irq, kvm_assigned_dev_intr,
+				0, "kvm_msi_assigned_device",
+				(void *)assigned_dev))
+			return -EIO;
+
+		assigned_dev->host_irq = assigned_dev->dev->irq;
+		assigned_dev->kvm = kvm;
+		assigned_dev->guest_intr_type = KVM_ASSIGNED_DEV_MSI;
+	}
+
+	assigned_dev->ack_notifier.gsi = -1;
+	return 0;
+}
+
 static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 				   struct kvm_assigned_irq
 				   *assigned_irq)
@@ -268,9 +358,24 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 		}
 	}
 
-	r = assigned_device_update_irq(kvm, match, assigned_irq);
-	if (r)
-		goto out_release;
+	if (assigned_irq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
+		if (assigned_device_update_msi(kvm, match, assigned_irq)) {
+			printk(KERN_INFO "kvm: fail to enable msi as guest "
+					 "requested, fall back to legacy "
+					 "interrupt\n");
+			r = -EINVAL;
+			if (assigned_device_update_irq(kvm, match,
+						assigned_irq)) {
+				printk(KERN_INFO "kvm: fail to fall back, "
+						 "release assigned device\n");
+				goto out_release;
+			}
+		}
+	} else {
+		r = assigned_device_update_irq(kvm, match, assigned_irq);
+		if (r)
+			goto out_release;
+	}
 
 	mutex_unlock(&kvm->lock);
 	return r;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 4269be1..b7890c1 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -493,9 +493,13 @@ struct kvm_assigned_irq {
 	__u32 assigned_dev_id;
 	__u32 host_irq;
 	__u32 guest_irq;
+	__u32 guest_msi_data;
+	__u32 guest_msi_addr;
 	__u32 flags;
 };
 
 #define KVM_DEV_ASSIGN_ENABLE_IOMMU	(1 << 0)
 
+#define KVM_DEV_IRQ_ASSIGN_ENABLE_MSI	(1 << 0)
+
 #endif
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index e24280b..1a3b4e4 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -300,8 +300,11 @@ struct kvm_assigned_dev_kernel {
 	int host_busnr;
 	int host_devfn;
 	int host_irq;
+	u32 guest_msi_addr;
+	u32 guest_msi_data;
 	int guest_irq;
 #define KVM_ASSIGNED_DEV_INTR	1
+#define KVM_ASSIGNED_DEV_MSI	2
 	int guest_intr_type;
 	struct pci_dev *dev;
 	struct kvm *kvm;
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index 53772bb..153ec2d 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -152,7 +152,7 @@ static void ioapic_inj_nmi(struct kvm_vcpu *vcpu)
 	kvm_inject_nmi(vcpu);
 }
 
-static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
 				       u8 dest_mode)
 {
 	u32 mask = 0;
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index b52732f..29b7e0a 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -92,5 +92,7 @@ void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
 int kvm_ioapic_init(struct kvm *kvm);
 void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
 void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
+u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
+				       u8 dest_mode);
 
 #endif
-- 
1.5.4.5


      parent reply	other threads:[~2008-10-08  8:39 UTC|newest]

Thread overview: 9+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-08  8:38 [PATCH 0/4] Clean up and enable MSI support for assigned device(v2) Sheng Yang
2008-10-08  8:38 ` [PATCH 1/4] Separate update irq to a single function Sheng Yang
2008-10-08 10:27   ` Sheng Yang
2008-10-08  8:38 ` [PATCH 2/4] KVM: x86: Replace irq_requested with guest_intr_type Sheng Yang
2008-10-08  8:38 ` [PATCH 3/4] x86: Add MSI delivery mode mask Sheng Yang
2008-10-08  8:48   ` Zhang, Xiantao
2008-10-08  8:52     ` Sheng Yang
2008-10-08  9:06       ` Zhang, Xiantao
2008-10-08  8:38 ` Sheng Yang [this message]

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=1223455093-304-5-git-send-email-sheng@linux.intel.com \
    --to=sheng@linux.intel.com \
    --cc=avi@redhat.com \
    --cc=kvm@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 an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.