Commit 4925663a authored by Gleb Natapov's avatar Gleb Natapov Committed by Avi Kivity

KVM: Report IRQ injection status to userspace.

IRQ injection status is either -1 (if there was no CPU found
that should except the interrupt because IRQ was masked or
ioapic was misconfigured or ...) or >= 0 in that case the
number indicates to how many CPUs interrupt was injected.
If the value is 0 it means that the interrupt was coalesced
and probably should be reinjected.
Signed-off-by: default avatarGleb Natapov <gleb@redhat.com>
Signed-off-by: default avatarAvi Kivity <avi@redhat.com>
parent 452425db
...@@ -182,7 +182,7 @@ int kvm_dev_ioctl_check_extension(long ext) ...@@ -182,7 +182,7 @@ int kvm_dev_ioctl_check_extension(long ext)
switch (ext) { switch (ext) {
case KVM_CAP_IRQCHIP: case KVM_CAP_IRQCHIP:
case KVM_CAP_MP_STATE: case KVM_CAP_MP_STATE:
case KVM_CAP_IRQ_INJECT_STATUS:
r = 1; r = 1;
break; break;
case KVM_CAP_COALESCED_MMIO: case KVM_CAP_COALESCED_MMIO:
...@@ -927,6 +927,7 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -927,6 +927,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
goto out; goto out;
} }
break; break;
case KVM_IRQ_LINE_STATUS:
case KVM_IRQ_LINE: { case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event; struct kvm_irq_level irq_event;
...@@ -934,10 +935,17 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -934,10 +935,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
if (copy_from_user(&irq_event, argp, sizeof irq_event)) if (copy_from_user(&irq_event, argp, sizeof irq_event))
goto out; goto out;
if (irqchip_in_kernel(kvm)) { if (irqchip_in_kernel(kvm)) {
__s32 status;
mutex_lock(&kvm->lock); 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); irq_event.irq, irq_event.level);
mutex_unlock(&kvm->lock); 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; r = 0;
} }
break; break;
......
...@@ -616,7 +616,7 @@ void kvm_queue_exception_e(struct kvm_vcpu *vcpu, unsigned nr, u32 error_code); ...@@ -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, void kvm_inject_page_fault(struct kvm_vcpu *vcpu, unsigned long cr2,
u32 error_code); 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); void kvm_inject_nmi(struct kvm_vcpu *vcpu);
......
...@@ -77,12 +77,13 @@ void kvm_pic_clear_isr_ack(struct kvm *kvm) ...@@ -77,12 +77,13 @@ void kvm_pic_clear_isr_ack(struct kvm *kvm)
/* /*
* set irq level. If an edge is detected, then the IRR is set to 1 * 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 = 1;
mask = 1 << irq; mask = 1 << irq;
if (s->elcr & mask) /* level triggered */ if (s->elcr & mask) /* level triggered */
if (level) { if (level) {
ret = !(s->irr & mask);
s->irr |= mask; s->irr |= mask;
s->last_irr |= mask; s->last_irr |= mask;
} else { } else {
...@@ -91,11 +92,15 @@ static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level) ...@@ -91,11 +92,15 @@ static inline void pic_set_irq1(struct kvm_kpic_state *s, int irq, int level)
} }
else /* edge triggered */ else /* edge triggered */
if (level) { if (level) {
if ((s->last_irr & mask) == 0) if ((s->last_irr & mask) == 0) {
ret = !(s->irr & mask);
s->irr |= mask; s->irr |= mask;
}
s->last_irr |= mask; s->last_irr |= mask;
} else } else
s->last_irr &= ~mask; s->last_irr &= ~mask;
return (s->imr & mask) ? -1 : ret;
} }
/* /*
...@@ -172,16 +177,19 @@ void kvm_pic_update_irq(struct kvm_pic *s) ...@@ -172,16 +177,19 @@ void kvm_pic_update_irq(struct kvm_pic *s)
pic_unlock(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; struct kvm_pic *s = opaque;
int ret = -1;
pic_lock(s); pic_lock(s);
if (irq >= 0 && irq < PIC_NUM_PINS) { 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_update_irq(s);
} }
pic_unlock(s); pic_unlock(s);
return ret;
} }
/* /*
......
...@@ -1019,6 +1019,7 @@ int kvm_dev_ioctl_check_extension(long ext) ...@@ -1019,6 +1019,7 @@ int kvm_dev_ioctl_check_extension(long ext)
case KVM_CAP_MP_STATE: case KVM_CAP_MP_STATE:
case KVM_CAP_SYNC_MMU: case KVM_CAP_SYNC_MMU:
case KVM_CAP_REINJECT_CONTROL: case KVM_CAP_REINJECT_CONTROL:
case KVM_CAP_IRQ_INJECT_STATUS:
r = 1; r = 1;
break; break;
case KVM_CAP_COALESCED_MMIO: case KVM_CAP_COALESCED_MMIO:
...@@ -1877,6 +1878,7 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1877,6 +1878,7 @@ long kvm_arch_vm_ioctl(struct file *filp,
create_pit_unlock: create_pit_unlock:
mutex_unlock(&kvm->lock); mutex_unlock(&kvm->lock);
break; break;
case KVM_IRQ_LINE_STATUS:
case KVM_IRQ_LINE: { case KVM_IRQ_LINE: {
struct kvm_irq_level irq_event; struct kvm_irq_level irq_event;
...@@ -1884,10 +1886,17 @@ long kvm_arch_vm_ioctl(struct file *filp, ...@@ -1884,10 +1886,17 @@ long kvm_arch_vm_ioctl(struct file *filp,
if (copy_from_user(&irq_event, argp, sizeof irq_event)) if (copy_from_user(&irq_event, argp, sizeof irq_event))
goto out; goto out;
if (irqchip_in_kernel(kvm)) { if (irqchip_in_kernel(kvm)) {
__s32 status;
mutex_lock(&kvm->lock); 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); irq_event.irq, irq_event.level);
mutex_unlock(&kvm->lock); 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; r = 0;
} }
break; break;
......
...@@ -48,7 +48,10 @@ struct kvm_irq_level { ...@@ -48,7 +48,10 @@ struct kvm_irq_level {
* For IA-64 (APIC model) IOAPIC0: irq 0-23; IOAPIC1: irq 24-47.. * 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.. * For X86 (standard AT mode) PIC0/1: irq 0-15. IOAPIC0: 0-23..
*/ */
union {
__u32 irq; __u32 irq;
__s32 status;
};
__u32 level; __u32 level;
}; };
...@@ -402,6 +405,7 @@ struct kvm_trace_rec { ...@@ -402,6 +405,7 @@ struct kvm_trace_rec {
#ifdef __KVM_HAVE_IOAPIC #ifdef __KVM_HAVE_IOAPIC
#define KVM_CAP_IRQ_ROUTING 25 #define KVM_CAP_IRQ_ROUTING 25
#endif #endif
#define KVM_CAP_IRQ_INJECT_STATUS 26
#ifdef KVM_CAP_IRQ_ROUTING #ifdef KVM_CAP_IRQ_ROUTING
...@@ -465,6 +469,7 @@ struct kvm_irq_routing { ...@@ -465,6 +469,7 @@ struct kvm_irq_routing {
#define KVM_CREATE_PIT _IO(KVMIO, 0x64) #define KVM_CREATE_PIT _IO(KVMIO, 0x64)
#define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state) #define KVM_GET_PIT _IOWR(KVMIO, 0x65, struct kvm_pit_state)
#define KVM_SET_PIT _IOR(KVMIO, 0x66, 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 \ #define KVM_REGISTER_COALESCED_MMIO \
_IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone) _IOW(KVMIO, 0x67, struct kvm_coalesced_mmio_zone)
#define KVM_UNREGISTER_COALESCED_MMIO \ #define KVM_UNREGISTER_COALESCED_MMIO \
......
...@@ -110,7 +110,7 @@ struct kvm_memory_slot { ...@@ -110,7 +110,7 @@ struct kvm_memory_slot {
struct kvm_kernel_irq_routing_entry { struct kvm_kernel_irq_routing_entry {
u32 gsi; 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); struct kvm *kvm, int level);
union { union {
struct { struct {
...@@ -352,7 +352,7 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq, ...@@ -352,7 +352,7 @@ void kvm_unregister_irq_mask_notifier(struct kvm *kvm, int irq,
struct kvm_irq_mask_notifier *kimn); struct kvm_irq_mask_notifier *kimn);
void kvm_fire_mask_notifiers(struct kvm *kvm, int irq, bool mask); 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 irqchip, unsigned pin); void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin);
void kvm_register_irq_ack_notifier(struct kvm *kvm, void kvm_register_irq_ack_notifier(struct kvm *kvm,
struct kvm_irq_ack_notifier *kian); struct kvm_irq_ack_notifier *kian);
......
...@@ -83,19 +83,22 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic, ...@@ -83,19 +83,22 @@ static unsigned long ioapic_read_indirect(struct kvm_ioapic *ioapic,
return result; 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; union ioapic_redir_entry *pent;
int injected = -1;
pent = &ioapic->redirtbl[idx]; pent = &ioapic->redirtbl[idx];
if (!pent->fields.mask) { if (!pent->fields.mask) {
int injected = ioapic_deliver(ioapic, idx); injected = ioapic_deliver(ioapic, idx);
if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG) if (injected && pent->fields.trig_mode == IOAPIC_LEVEL_TRIG)
pent->fields.remote_irr = 1; pent->fields.remote_irr = 1;
} }
if (!pent->fields.trig_mode) if (!pent->fields.trig_mode)
ioapic->irr &= ~(1 << idx); ioapic->irr &= ~(1 << idx);
return injected;
} }
static void ioapic_write_indirect(struct kvm_ioapic *ioapic, u32 val) 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) ...@@ -207,7 +210,7 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode; u8 trig_mode = ioapic->redirtbl[irq].fields.trig_mode;
u32 deliver_bitmask; u32 deliver_bitmask;
struct kvm_vcpu *vcpu; struct kvm_vcpu *vcpu;
int vcpu_id, r = 0; int vcpu_id, r = -1;
ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x " ioapic_debug("dest=%x dest_mode=%x delivery_mode=%x "
"vector=%x trig_mode=%x\n", "vector=%x trig_mode=%x\n",
...@@ -247,7 +250,9 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) ...@@ -247,7 +250,9 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
deliver_bitmask &= ~(1 << vcpu_id); deliver_bitmask &= ~(1 << vcpu_id);
vcpu = ioapic->kvm->vcpus[vcpu_id]; vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) { if (vcpu) {
r = ioapic_inj_irq(ioapic, vcpu, vector, if (r < 0)
r = 0;
r += ioapic_inj_irq(ioapic, vcpu, vector,
trig_mode, delivery_mode); trig_mode, delivery_mode);
} }
} }
...@@ -258,8 +263,10 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) ...@@ -258,8 +263,10 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
continue; continue;
deliver_bitmask &= ~(1 << vcpu_id); deliver_bitmask &= ~(1 << vcpu_id);
vcpu = ioapic->kvm->vcpus[vcpu_id]; vcpu = ioapic->kvm->vcpus[vcpu_id];
if (vcpu) if (vcpu) {
ioapic_inj_nmi(vcpu); ioapic_inj_nmi(vcpu);
r = 1;
}
else else
ioapic_debug("NMI to vcpu %d failed\n", ioapic_debug("NMI to vcpu %d failed\n",
vcpu->vcpu_id); vcpu->vcpu_id);
...@@ -273,11 +280,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq) ...@@ -273,11 +280,12 @@ static int ioapic_deliver(struct kvm_ioapic *ioapic, int irq)
return r; 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 old_irr = ioapic->irr;
u32 mask = 1 << irq; u32 mask = 1 << irq;
union ioapic_redir_entry entry; union ioapic_redir_entry entry;
int ret = 1;
if (irq >= 0 && irq < IOAPIC_NUM_PINS) { if (irq >= 0 && irq < IOAPIC_NUM_PINS) {
entry = ioapic->redirtbl[irq]; entry = ioapic->redirtbl[irq];
...@@ -288,9 +296,10 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level) ...@@ -288,9 +296,10 @@ void kvm_ioapic_set_irq(struct kvm_ioapic *ioapic, int irq, int level)
ioapic->irr |= mask; ioapic->irr |= mask;
if ((!entry.fields.trig_mode && old_irr != ioapic->irr) if ((!entry.fields.trig_mode && old_irr != ioapic->irr)
|| !entry.fields.remote_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 pin, static void __kvm_ioapic_update_eoi(struct kvm_ioapic *ioapic, int pin,
......
...@@ -83,7 +83,7 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector, ...@@ -83,7 +83,7 @@ struct kvm_vcpu *kvm_get_lowest_prio_vcpu(struct kvm *kvm, u8 vector,
unsigned long bitmap); unsigned long bitmap);
void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode); void kvm_ioapic_update_eoi(struct kvm *kvm, int vector, int trigger_mode);
int kvm_ioapic_init(struct kvm *kvm); 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); void kvm_ioapic_reset(struct kvm_ioapic *ioapic);
u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest, u32 kvm_ioapic_get_delivery_bitmask(struct kvm_ioapic *ioapic, u8 dest,
u8 dest_mode); u8 dest_mode);
......
...@@ -29,21 +29,23 @@ ...@@ -29,21 +29,23 @@
#include "ioapic.h" #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) struct kvm *kvm, int level)
{ {
#ifdef CONFIG_X86 #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 #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) 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);
} }
static void kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, static int kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
struct kvm *kvm, int level) struct kvm *kvm, int level)
{ {
int vcpu_id; int vcpu_id;
...@@ -88,13 +90,20 @@ static void kvm_set_msi(struct kvm_kernel_irq_routing_entry *e, ...@@ -88,13 +90,20 @@ static void kvm_set_msi(struct kvm_kernel_irq_routing_entry *e,
default: default:
break; break;
} }
return 1;
} }
/* This should be called with the kvm->lock mutex held */ /* 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) * Return value:
* < 0 Interrupt was ignored (masked or not delivered for other reasons)
* = 0 Interrupt was coalesced (previous irq is still pending)
* > 0 Number of CPUs interrupt was delivered to
*/
int kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
{ {
struct kvm_kernel_irq_routing_entry *e; struct kvm_kernel_irq_routing_entry *e;
unsigned long *irq_state, sig_level; unsigned long *irq_state, sig_level;
int ret = -1;
if (irq < KVM_IOAPIC_NUM_PINS) { if (irq < KVM_IOAPIC_NUM_PINS) {
irq_state = (unsigned long *)&kvm->arch.irq_states[irq]; irq_state = (unsigned long *)&kvm->arch.irq_states[irq];
...@@ -113,8 +122,14 @@ void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level) ...@@ -113,8 +122,14 @@ void kvm_set_irq(struct kvm *kvm, int irq_source_id, int irq, int level)
* writes to the unused one. * writes to the unused one.
*/ */
list_for_each_entry(e, &kvm->irq_routing, link) list_for_each_entry(e, &kvm->irq_routing, link)
if (e->gsi == irq) if (e->gsi == irq) {
e->set(e, kvm, sig_level); int r = e->set(e, kvm, sig_level);
if (r < 0)
continue;
ret = r + ((ret < 0) ? 0 : ret);
}
return ret;
} }
void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin) void kvm_notify_acked_irq(struct kvm *kvm, unsigned irqchip, unsigned pin)
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment