mirror of
https://github.com/adulau/aha.git
synced 2024-12-28 03:36:19 +00:00
KVM: Use irq routing API for MSI
Merge MSI userspace interface with IRQ routing table. Notice the API have been changed, and using IRQ routing table would be the only interface kvm-userspace supported. Signed-off-by: Sheng Yang <sheng@linux.intel.com> Signed-off-by: Avi Kivity <avi@redhat.com>
This commit is contained in:
parent
34c33d163f
commit
79950e1073
4 changed files with 86 additions and 73 deletions
|
@ -410,8 +410,16 @@ struct kvm_irq_routing_irqchip {
|
|||
__u32 pin;
|
||||
};
|
||||
|
||||
struct kvm_irq_routing_msi {
|
||||
__u32 address_lo;
|
||||
__u32 address_hi;
|
||||
__u32 data;
|
||||
__u32 pad;
|
||||
};
|
||||
|
||||
/* gsi routing entry types */
|
||||
#define KVM_IRQ_ROUTING_IRQCHIP 1
|
||||
#define KVM_IRQ_ROUTING_MSI 2
|
||||
|
||||
struct kvm_irq_routing_entry {
|
||||
__u32 gsi;
|
||||
|
@ -420,6 +428,7 @@ struct kvm_irq_routing_entry {
|
|||
__u32 pad;
|
||||
union {
|
||||
struct kvm_irq_routing_irqchip irqchip;
|
||||
struct kvm_irq_routing_msi msi;
|
||||
__u32 pad[8];
|
||||
} u;
|
||||
};
|
||||
|
|
|
@ -116,6 +116,7 @@ struct kvm_kernel_irq_routing_entry {
|
|||
unsigned irqchip;
|
||||
unsigned pin;
|
||||
} irqchip;
|
||||
struct msi_msg msi;
|
||||
};
|
||||
struct list_head link;
|
||||
};
|
||||
|
@ -327,7 +328,6 @@ struct kvm_assigned_dev_kernel {
|
|||
int host_irq;
|
||||
bool host_irq_disabled;
|
||||
int guest_irq;
|
||||
struct msi_msg guest_msi;
|
||||
#define KVM_ASSIGNED_DEV_GUEST_INTX (1 << 0)
|
||||
#define KVM_ASSIGNED_DEV_GUEST_MSI (1 << 1)
|
||||
#define KVM_ASSIGNED_DEV_HOST_INTX (1 << 8)
|
||||
|
|
|
@ -20,6 +20,11 @@
|
|||
*/
|
||||
|
||||
#include <linux/kvm_host.h>
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/msidef.h>
|
||||
#endif
|
||||
|
||||
#include "irq.h"
|
||||
|
||||
#include "ioapic.h"
|
||||
|
@ -38,17 +43,70 @@ static void kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
|
|||
kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
|
||||
}
|
||||
|
||||
static void kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
|
||||
struct kvm *kvm, int level)
|
||||
{
|
||||
int vcpu_id;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_ioapic *ioapic = ioapic_irqchip(kvm);
|
||||
int dest_id = (e->msi.address_lo & MSI_ADDR_DEST_ID_MASK)
|
||||
>> MSI_ADDR_DEST_ID_SHIFT;
|
||||
int vector = (e->msi.data & MSI_DATA_VECTOR_MASK)
|
||||
>> MSI_DATA_VECTOR_SHIFT;
|
||||
int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
|
||||
(unsigned long *)&e->msi.address_lo);
|
||||
int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
|
||||
(unsigned long *)&e->msi.data);
|
||||
int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT,
|
||||
(unsigned long *)&e->msi.data);
|
||||
u32 deliver_bitmask;
|
||||
|
||||
BUG_ON(!ioapic);
|
||||
|
||||
deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
|
||||
dest_id, dest_mode);
|
||||
/* IOAPIC delivery mode value is the same as MSI here */
|
||||
switch (delivery_mode) {
|
||||
case IOAPIC_LOWEST_PRIORITY:
|
||||
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 "kvm: null lowest priority vcpu!\n");
|
||||
break;
|
||||
case IOAPIC_FIXED:
|
||||
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:
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* This should be called with the kvm->lock mutex held */
|
||||
void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
|
||||
{
|
||||
struct kvm_kernel_irq_routing_entry *e;
|
||||
unsigned long *irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
|
||||
unsigned long *irq_state, sig_level;
|
||||
|
||||
/* Logical OR for level trig interrupt */
|
||||
if (level)
|
||||
set_bit(irq_source_id, irq_state);
|
||||
else
|
||||
clear_bit(irq_source_id, irq_state);
|
||||
if (irq < KVM_IOAPIC_NUM_PINS) {
|
||||
irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
|
||||
|
||||
/* Logical OR for level trig interrupt */
|
||||
if (level)
|
||||
set_bit(irq_source_id, irq_state);
|
||||
else
|
||||
clear_bit(irq_source_id, irq_state);
|
||||
sig_level = !!(*irq_state);
|
||||
} else /* Deal with MSI/MSI-X */
|
||||
sig_level = 1;
|
||||
|
||||
/* Not possible to detect if the guest uses the PIC or the
|
||||
* IOAPIC. So set the bit in both. The guest will ignore
|
||||
|
@ -56,7 +114,7 @@ void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
|
|||
*/
|
||||
list_for_each_entry(e, &kvm->irq_routing, link)
|
||||
if (e->gsi == irq)
|
||||
e->set(e, kvm, !!(*irq_state));
|
||||
e->set(e, kvm, sig_level);
|
||||
}
|
||||
|
||||
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
|
||||
|
@ -186,6 +244,12 @@ int setup_routing_entry(struct kvm_kernel_irq_routing_entry *e,
|
|||
e->irqchip.irqchip = ue->u.irqchip.irqchip;
|
||||
e->irqchip.pin = ue->u.irqchip.pin + delta;
|
||||
break;
|
||||
case KVM_IRQ_ROUTING_MSI:
|
||||
e->set = kvm_set_msi;
|
||||
e->msi.address_lo = ue->u.msi.address_lo;
|
||||
e->msi.address_hi = ue->u.msi.address_hi;
|
||||
e->msi.data = ue->u.msi.data;
|
||||
break;
|
||||
default:
|
||||
goto out;
|
||||
}
|
||||
|
|
|
@ -47,10 +47,6 @@
|
|||
#include <asm/uaccess.h>
|
||||
#include <asm/pgtable.h>
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
#include <asm/msidef.h>
|
||||
#endif
|
||||
|
||||
#ifdef KVM_COALESCED_MMIO_PAGE_OFFSET
|
||||
#include "coalesced_mmio.h"
|
||||
#endif
|
||||
|
@ -85,57 +81,6 @@ static long kvm_vcpu_ioctl(struct file *file, unsigned int ioctl,
|
|||
static bool kvm_rebooting;
|
||||
|
||||
#ifdef KVM_CAP_DEVICE_ASSIGNMENT
|
||||
|
||||
#ifdef CONFIG_X86
|
||||
static void assigned_device_msi_dispatch(struct kvm_assigned_dev_kernel *dev)
|
||||
{
|
||||
int vcpu_id;
|
||||
struct kvm_vcpu *vcpu;
|
||||
struct kvm_ioapic *ioapic = ioapic_irqchip(dev->kvm);
|
||||
int dest_id = (dev->guest_msi.address_lo & MSI_ADDR_DEST_ID_MASK)
|
||||
>> MSI_ADDR_DEST_ID_SHIFT;
|
||||
int vector = (dev->guest_msi.data & MSI_DATA_VECTOR_MASK)
|
||||
>> MSI_DATA_VECTOR_SHIFT;
|
||||
int dest_mode = test_bit(MSI_ADDR_DEST_MODE_SHIFT,
|
||||
(unsigned long *)&dev->guest_msi.address_lo);
|
||||
int trig_mode = test_bit(MSI_DATA_TRIGGER_SHIFT,
|
||||
(unsigned long *)&dev->guest_msi.data);
|
||||
int delivery_mode = test_bit(MSI_DATA_DELIVERY_MODE_SHIFT,
|
||||
(unsigned long *)&dev->guest_msi.data);
|
||||
u32 deliver_bitmask;
|
||||
|
||||
BUG_ON(!ioapic);
|
||||
|
||||
deliver_bitmask = kvm_ioapic_get_delivery_bitmask(ioapic,
|
||||
dest_id, dest_mode);
|
||||
/* IOAPIC delivery mode value is the same as MSI here */
|
||||
switch (delivery_mode) {
|
||||
case IOAPIC_LOWEST_PRIORITY:
|
||||
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 "kvm: null lowest priority vcpu!\n");
|
||||
break;
|
||||
case IOAPIC_FIXED:
|
||||
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 "kvm: unsupported MSI delivery mode\n");
|
||||
}
|
||||
}
|
||||
#else
|
||||
static void assigned_device_msi_dispatch(struct kvm_assigned_dev_kernel *dev) {}
|
||||
#endif
|
||||
|
||||
static struct kvm_assigned_dev_kernel *kvm_find_assigned_dev(struct list_head *head,
|
||||
int assigned_dev_id)
|
||||
{
|
||||
|
@ -162,13 +107,10 @@ static void kvm_assigned_dev_interrupt_work_handler(struct work_struct *work)
|
|||
* finer-grained lock, update this
|
||||
*/
|
||||
mutex_lock(&assigned_dev->kvm->lock);
|
||||
if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_INTX)
|
||||
kvm_set_irq(assigned_dev->kvm,
|
||||
assigned_dev->irq_source_id,
|
||||
assigned_dev->guest_irq, 1);
|
||||
else if (assigned_dev->irq_requested_type &
|
||||
KVM_ASSIGNED_DEV_GUEST_MSI) {
|
||||
assigned_device_msi_dispatch(assigned_dev);
|
||||
kvm_set_irq(assigned_dev->kvm, assigned_dev->irq_source_id,
|
||||
assigned_dev->guest_irq, 1);
|
||||
|
||||
if (assigned_dev->irq_requested_type & KVM_ASSIGNED_DEV_GUEST_MSI) {
|
||||
enable_irq(assigned_dev->host_irq);
|
||||
assigned_dev->host_irq_disabled = false;
|
||||
}
|
||||
|
@ -331,17 +273,15 @@ static int assigned_device_update_msi(struct kvm *kvm,
|
|||
{
|
||||
int r;
|
||||
|
||||
adev->guest_irq = airq->guest_irq;
|
||||
if (airq->flags & KVM_DEV_IRQ_ASSIGN_ENABLE_MSI) {
|
||||
/* x86 don't care upper address of guest msi message addr */
|
||||
adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_MSI;
|
||||
adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_INTX;
|
||||
adev->guest_msi.address_lo = airq->guest_msi.addr_lo;
|
||||
adev->guest_msi.data = airq->guest_msi.data;
|
||||
adev->ack_notifier.gsi = -1;
|
||||
} else if (msi2intx) {
|
||||
adev->irq_requested_type |= KVM_ASSIGNED_DEV_GUEST_INTX;
|
||||
adev->irq_requested_type &= ~KVM_ASSIGNED_DEV_GUEST_MSI;
|
||||
adev->guest_irq = airq->guest_irq;
|
||||
adev->ack_notifier.gsi = airq->guest_irq;
|
||||
} else {
|
||||
/*
|
||||
|
|
Loading…
Reference in a new issue