Signed-off-by: Gleb Natapov <[email protected]>
diff --git a/arch/ia64/kvm/kvm-ia64.c b/arch/ia64/kvm/kvm-ia64.c
index 9c77e39..076b00d 100644
--- a/arch/ia64/kvm/kvm-ia64.c
+++ b/arch/ia64/kvm/kvm-ia64.c
@@ -182,7 +182,7 @@ int kvm_dev_ioctl_check_extension(long ext)
switch (ext) {
case KVM_CAP_IRQCHIP:
case KVM_CAP_MP_STATE:
-
+ case KVM_CAP_IRQ_INJECT_STATUS:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -927,6 +927,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out;
}
break;
+ case KVM_IRQ_LINE_STATUS:
case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event;
@@ -934,10 +935,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
if (copy_from_user(&irq_event, argp, sizeof irq_event))
goto out;
if (irqchip_in_kernel(kvm)) {
+ __s32 status;
mutex_lock(&kvm->lock);
- kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+ status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
irq_event.irq, irq_event.level);
mutex_unlock(&kvm->lock);
+ if (ioctl == KVM_IRQ_LINE_STATUS) {
+ irq_event.status = status;
+ if (copy_to_user(argp, &irq_event,
+ sizeof irq_event))
+ goto out;
+ }
r = 0;
}
break;
diff --git a/arch/x86/include/asm/kvm_host.h b/arch/x86/include/asm/kvm_host.h
index 55fd4c5..f0faf58 100644
--- a/arch/x86/include/asm/kvm_host.h
+++ b/arch/x86/include/asm/kvm_host.h
@@ -616,7 +616,7 @@ void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned
nr, u32 error_code);
void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
u32 error_code);
-void kvm_pic_set_irq(void *opaque, int irq, int level);
+int kvm_pic_set_irq(void *opaque, int irq, int level);
void kvm_inject_nmi(struct kvm_vcpu *vcpu);
diff --git a/arch/x86/kvm/i8259.c b/arch/x86/kvm/i8259.c
index 179dcb0..712b962 100644
--- a/arch/x86/kvm/i8259.c
+++ b/arch/x86/kvm/i8259.c
@@ -76,12 +76,14 @@ void kvm_pic_clear_isr_ack(struct kvm *kvm)
/*
* set irq level. If an edge is detected, then the IRR is set to 1
*/
-static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
+static inline int pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
{
- int mask;
+ int mask, ret = KVM_IRQ_INJECTED;
mask = 1 << irq;
if (s->elcr & mask) /* level triggered */
if (level) {
+ if (s->irr & mask)
+ ret = KVM_IRQ_COALESCED;
s->irr |= mask;
s->last_irr |= mask;
} else {
@@ -90,11 +92,19 @@ static inline void pic_set_irq1(struct kvm_kpic_state *s,
int irq, int level)
}
else /* edge triggered */
if (level) {
- if ((s->last_irr & mask) == 0)
+ if ((s->last_irr & mask) == 0) {
+ if (s->irr & mask)
+ ret = KVM_IRQ_COALESCED;
s->irr |= mask;
+ }
s->last_irr |= mask;
} else
s->last_irr &= ~mask;
+
+ if (s->imr & mask)
+ ret = KVM_IRQ_IGNORED;
+
+ return ret;
}
/*
@@ -171,16 +181,19 @@ void kvm_pic_update_irq(struct kvm_pic *s)
pic_unlock(s);
}
-void kvm_pic_set_irq(void *opaque, int irq, int level)
+int kvm_pic_set_irq(void *opaque, int irq, int level)
{
struct kvm_pic *s = opaque;
+ int ret = KVM_IRQ_IGNORED;
pic_lock(s);
if (irq >= 0 && irq < PIC_NUM_PINS) {
- pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
+ ret = pic_set_irq1(&s->pics[irq >> 3], irq & 7, level);
pic_update_irq(s);
}
pic_unlock(s);
+
+ return ret;
}
/*
diff --git a/arch/x86/kvm/lapic.c b/arch/x86/kvm/lapic.c
index d8adc50..4d44b34 100644
--- a/arch/x86/kvm/lapic.c
+++ b/arch/x86/kvm/lapic.c
@@ -201,9 +201,9 @@ int kvm_apic_set_irq(struct kvm_vcpu *vcpu, u8 vec, u8 trig)
else
apic_clear_vector(vec, apic->regs + APIC_TMR);
kvm_vcpu_kick(apic->vcpu);
- return 1;
+ return KVM_IRQ_INJECTED;
}
- return 0;
+ return KVM_IRQ_COALESCED;
}
static inline int apic_find_highest_isr(struct kvm_lapic *apic)
diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c
index e96edda..5754c37 100644
--- a/arch/x86/kvm/x86.c
+++ b/arch/x86/kvm/x86.c
@@ -995,6 +995,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_MP_STATE:
case KVM_CAP_SYNC_MMU:
case KVM_CAP_REINJECT_CONTROL:
+ case KVM_CAP_IRQ_INJECT_STATUS:
r = 1;
break;
case KVM_CAP_COALESCED_MMIO:
@@ -1852,6 +1853,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
create_pit_unlock:
mutex_unlock(&kvm->lock);
break;
+ case KVM_IRQ_LINE_STATUS:
case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event;
@@ -1859,10 +1861,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
if (copy_from_user(&irq_event, argp, sizeof irq_event))
goto out;
if (irqchip_in_kernel(kvm)) {
+ __s32 status;
mutex_lock(&kvm->lock);
- kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
- irq_event.irq, irq_event.level);
+ status = kvm_set_irq(kvm, KVM_USERSPACE_IRQ_SOURCE_ID,
+ irq_event.irq, irq_event.level);
mutex_unlock(&kvm->lock);
+ if (ioctl == KVM_IRQ_LINE_STATUS) {
+ irq_event.status = status;
+ if (copy_to_user(argp, &irq_event,
+ sizeof irq_event))
+ goto out;
+ }
r = 0;
}
break;
diff --git a/include/linux/kvm.h b/include/linux/kvm.h
index 869462c..7a6638c 100644
--- a/include/linux/kvm.h
+++ b/include/linux/kvm.h
@@ -40,6 +40,9 @@ struct kvm_userspace_memory_region {
/* for kvm_memory_region::flags */
#define KVM_MEM_LOG_DIRTY_PAGES 1UL
+#define KVM_IRQ_IGNORED -1
+#define KVM_IRQ_COALESCED 0
+#define KVM_IRQ_INJECTED 1
/* for KVM_IRQ_LINE */
struct kvm_irq_level {
@@ -48,7 +51,10 @@ struct kvm_irq_level {
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47..
* For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
*/
- __u32 irq;
+ union {
+ __u32 irq;
+ __s32 status;
+ };
__u32 level;
};
@@ -402,6 +408,7 @@ struct kvm_trace_rec {
#ifdef __KVM_HAVE_IOAPIC
#define KVM_CAP_IRQ_ROUTING 25
#endif
+#define KVM_CAP_IRQ_INJECT_STATUS 26
#ifdef KVM_CAP_IRQ_ROUTING
@@ -456,6 +463,7 @@ struct kvm_irq_routing {
#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
#define KVM_SET_PIT _IOR(KVMIO, 0x66, struct kvm_pit_state)
+#define KVM_IRQ_LINE_STATUS _IOWR(KVMIO, 0x67, struct kvm_irq_level)
#define KVM_REGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
#define KVM_UNREGISTER_COALESCED_MMIO \
diff --git a/include/linux/kvm_host.h b/include/linux/kvm_host.h
index ce285e0..a8f91bb 100644
--- a/include/linux/kvm_host.h
+++ b/include/linux/kvm_host.h
@@ -109,7 +109,7 @@ struct kvm_memory_slot {
struct kvm_kernel_irq_routing_entry {
u32 gsi;
- void (*set)(struct kvm_kernel_irq_routing_entry *e,
+ int (*set)(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level);
union {
struct {
@@ -351,7 +351,7 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int
irq,
struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask);
-void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
+int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level);
void kvm_notify_acked_irq(struct kvm *kvm, unsigned gsi);
void kvm_register_irq_ack_notifier(struct kvm *kvm,
struct kvm_irq_ack_notifier *kian);
diff --git a/virt/kvm/ioapic.c b/virt/kvm/ioapic.c
index e85a2bc..fc6c8f6 100644
--- a/virt/kvm/ioapic.c
+++ b/virt/kvm/ioapic.c
@@ -83,19 +83,22 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic
*ioapic,
return result;
}
-static void ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
+static int ioapic_service(struct kvm_ioapic *ioapic, unsigned int idx)
{
union ioapic_redir_entry *pent;
+ int injected = KVM_IRQ_IGNORED;
pent = &ioapic->redirtbl[idx];
if (!pent->fields.mask) {
- int injected = ioapic_deliver(ioapic, idx);
+ injected = ioapic_deliver(ioapic, idx);
if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
pent->fields.remote_irr = 1;
}
if (!pent->fields.trig_mode)
ioapic->irr &= ~(1 << idx);
+
+ return injected;
}
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val)
@@ -207,7 +210,7 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int
irq)
u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
u32 deliver_bitmask;
struct kvm_vcpu *vcpu;
- int vcpu_id, r = 0;
+ int vcpu_id, r = KVM_IRQ_IGNORED;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n",
@@ -247,8 +250,10 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int
irq)
deliver_bitmask &= ~(1 << vcpu_id);
vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) {
- r = ioapic_inj_irq(ioapic, vcpu, vector,
+ int s;
+ s = ioapic_inj_irq(ioapic, vcpu, vector,
trig_mode, delivery_mode);
+ r = max(r, s);
}
}
break;
@@ -258,8 +263,10 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int
irq)
continue;
deliver_bitmask &= ~(1 << vcpu_id);
vcpu = ioapic->kvm->vcpus[vcpu_id];
- if (vcpu)
+ if (vcpu) {
ioapic_inj_nmi(vcpu);
+ r = KVM_IRQ_INJECTED;
+ }
else
ioapic_debug("NMI to vcpu %d failed\n",
vcpu->vcpu_id);
@@ -273,11 +280,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int
irq)
return r;
}
-void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
+int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
{
u32 old_irr = ioapic->irr;
u32 mask = 1 << irq;
union ioapic_redir_entry entry;
+ int ret = 1;
if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
entry = ioapic->redirtbl[irq];
@@ -288,9 +296,10 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int
irq, int level)
ioapic->irr |= mask;
if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
|| !entry.fields.remote_irr)
- ioapic_service(ioapic, irq);
+ ret = ioapic_service(ioapic, irq);
}
}
+ return ret;
}
static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int gsi,
diff --git a/virt/kvm/ioapic.h b/virt/kvm/ioapic.h
index 49c9581..a34bd5e 100644
--- a/virt/kvm/ioapic.h
+++ b/virt/kvm/ioapic.h
@@ -83,7 +83,7 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8
vector,
unsigned long bitmap);
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);
+int kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level);
void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
u8 dest_mode);
diff --git a/virt/kvm/irq_comm.c b/virt/kvm/irq_comm.c
index a797fa5..00bb29f 100644
--- a/virt/kvm/irq_comm.c
+++ b/virt/kvm/irq_comm.c
@@ -24,25 +24,28 @@
#include "ioapic.h"
-static void kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
+static int kvm_set_pic_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level)
{
#ifdef CONFIG_X86
- kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level);
+ return kvm_pic_set_irq(pic_irqchip(kvm), e->irqchip.pin, level);
+#else
+ return -1;
#endif
}
-static void kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
+static int kvm_set_ioapic_irq(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level)
{
- kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
+ return kvm_ioapic_set_irq(kvm->arch.vioapic, e->irqchip.pin, level);
}
/* 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)
+int 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];
+ int ret = -1;
/* Logical OR for level trig interrupt */
if (level)
@@ -55,8 +58,11 @@ void kvm_set_irq(struct kvm *kvm, int irq_source_id, int
irq, int level)
* writes to the unused one.
*/
list_for_each_entry(e, &kvm->irq_routing, link)
- if (e->gsi == irq)
- e->set(e, kvm, !!(*irq_state));
+ if (e->gsi == irq) {
+ int r = e->set(e, kvm, !!(*irq_state));
+ ret = max(ret, r);
+ }
+ return ret;
}
void kvm_notify_acked_irq(struct kvm *kvm, unsigned gsi)
@@ -165,7 +171,7 @@ int setup_routing_entry(struct kvm_kernel_irq_routing_entry
*e,
e->set = kvm_set_pic_irq;
break;
case KVM_IRQCHIP_PIC_SLAVE:
- e->set = kvm_set_pic_irq;
+ e->set = kvm_set_pic_irq;
delta = 8;
break;
case KVM_IRQCHIP_IOAPIC:
--
Gleb.
--
To unsubscribe from this list: send the line "unsubscribe kvm" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html