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, weidong.han@intel.com, allen.m.kay@intel.com
Subject: Re: [PATCH 4/4] KVM: x86: Enable MSI for assigned device
Date: Tue, 7 Oct 2008 14:09:16 +0800	[thread overview]
Message-ID: <20081007060916.GA1116@syang10-desktop> (raw)

Update according to the comments. Thanks!

--
From: Sheng Yang <sheng@linux.intel.com>
Date: Tue, 7 Oct 2008 14:04:24 +0800
Subject: [PATCH 4/4] KVM: x86: Enable MSI for assigned device

As well as export ioapic_get_delivery_bitmask().

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 4836323..3e39485 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -40,6 +40,7 @@
 #include <asm/uaccess.h>
 #include <asm/msr.h>
 #include <asm/desc.h>
+#include <asm/msidef.h>
 
 #define MAX_IO_MSRS 256
 #define CR0_RESERVED_BITS						\
@@ -120,6 +121,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;
@@ -132,8 +177,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);
 }
@@ -172,6 +221,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);
 
@@ -215,6 +266,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;
 
@@ -241,6 +297,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)
@@ -261,9 +351,24 @@ static int kvm_vm_ioctl_assign_irq(struct kvm *kvm,
 		INIT_WORK(&match->interrupt_work,
 				kvm_assigned_dev_interrupt_work_handler);
 
-	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


             reply	other threads:[~2008-10-07  6:10 UTC|newest]

Thread overview: 7+ messages / expand[flat|nested]  mbox.gz  Atom feed  top
2008-10-07  6:09 Sheng Yang [this message]
  -- strict thread matches above, loose matches on Subject: below --
2008-09-26  5:17 [PATCH 4/4] KVM: x86: Enable MSI for assigned device Sheng Yang
2008-10-05 10:27 ` Avi Kivity
2008-10-06  3:36   ` Yang, Sheng
2008-10-07  5:59     ` Sheng Yang
2008-10-07 13:42       ` Avi Kivity
2008-10-08  2:55         ` Sheng Yang

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=20081007060916.GA1116@syang10-desktop \
    --to=sheng@linux.intel.com \
    --cc=allen.m.kay@intel.com \
    --cc=avi@redhat.com \
    --cc=kvm@vger.kernel.org \
    --cc=weidong.han@intel.com \
    /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.