From: Sheng Yang <sheng.yang@intel.com>
To: Avi Kivity <avi@redhat.com>
Cc: kvm@vger.kernel.org, "Weidong\"" <weidong.han@intel.com>,
"Allen M\"" <allen.m.kay@intel.com>,
Sheng Yang <sheng.yang@intel.com>
Subject: [PATCH 4/4] KVM: x86: Enable MSI for assigned device
Date: Fri, 26 Sep 2008 13:17:35 +0800 [thread overview]
Message-ID: <1222406255-27727-5-git-send-email-sheng.yang@intel.com> (raw)
In-Reply-To: <>
As well as export ioapic_get_delivery_bitmask().
Signed-off-by: Sheng Yang <sheng.yang@intel.com>
---
arch/x86/kvm/x86.c | 111 +++++++++++++++++++++++++++++++++++++++++++--
include/linux/kvm.h | 4 ++
include/linux/kvm_host.h | 3 +
virt/kvm/ioapic.c | 3 +-
virt/kvm/ioapic.h | 2 +
5 files changed, 117 insertions(+), 6 deletions(-)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index 4836323..66d96e2 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,20 @@ 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, fall"
+ " back to legacy interrupt\n");
+ if (assigned_device_update_irq(kvm, match,
+ assigned_irq))
+ 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..a9b408b 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;
+ __u16 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..dc6a046 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;
+ u16 guest_msi_addr;
+ u16 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..fbc329f 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;
@@ -191,6 +191,7 @@ static u32 ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
ioapic_debug("mask %x\n", mask);
return mask;
}
+EXPORT_SYMBOL_GPL(ioapic_get_delivery_bitmask);
static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
{
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
next reply other threads:[~2008-09-26 5:16 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2008-09-26 5:17 Sheng Yang [this message]
2008-10-05 10:27 ` [PATCH 4/4] KVM: x86: Enable MSI for assigned device 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
-- strict thread matches above, loose matches on Subject: below --
2008-10-07 6:09 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=1222406255-27727-5-git-send-email-sheng.yang@intel.com \
--to=sheng.yang@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.