report IRQ injection status to userspace.
PATCH 1/1 report IRQ injection status to userspace.
arch/x86/include/asm/kvm_host.h +1 -1
@@ -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);
arch/x86/kvm/i8259.c +12 -5
@@ -76,9 +76,9 @@ 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 =1 ; mask =1 << irq;if (s->elcr & mask)/* level triggered */ if (level) {
@@ -90,11 +90,15 @@ 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 ) { + ret = !(s->irr & mask); s->irr |= mask; + } s->last_irr |= mask; }else s->last_irr &= ~mask; + +return (s->imr & mask) ?-1 : ret; }/*
@@ -171,16 +175,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 =-1 ;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; }/*
arch/x86/kvm/x86.c +5 -2
@@ -1860,9 +1860,12 @@ long kvm_arch_vm_ioctl(struct file *filp, goto out;if (irqchip_in_kernel (kvm)) {mutex_lock (&kvm->lock); -kvm_set_irq (kvm,KVM_USERSPACE_IRQ_SOURCE_ID , - irq_event.irq, irq_event.level); + irq_event.status = +kvm_set_irq (kvm,KVM_USERSPACE_IRQ_SOURCE_ID , + irq_event.irq, irq_event.level);mutex_unlock (&kvm->lock); +if (copy_to_user (argp, &irq_event,sizeof irq_event)) + goto out; r =0 ; }break ;
include/linux/kvm.h +5 -2
@@ -48,7 +48,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; };
@@ -450,7 +453,7 @@ struct kvm_irq_routing {#define KVM_SET_MEMORY_ALIAS _IOW(KVMIO, 0x43, struct kvm_memory_alias)/* Device model IOC */ #define KVM_CREATE_IRQCHIP _IO(KVMIO, 0x60) -#define KVM_IRQ_LINE _IOW(KVMIO, 0x61, struct kvm_irq_level) +#define KVM_IRQ_LINE _IOWR(KVMIO, 0x61, struct kvm_irq_level)#define KVM_GET_IRQCHIP _IOWR(KVMIO, 0x62, struct kvm_irqchip)#define KVM_SET_IRQCHIP _IOR(KVMIO, 0x63, struct kvm_irqchip)#define KVM_CREATE_PIT _IO(KVMIO, 0x64)
include/linux/kvm_host.h +2 -2
@@ -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);
virt/kvm/ioapic.c +9 -4
@@ -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 =-1 ; 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)
@@ -273,11 +276,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 +292,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,
virt/kvm/ioapic.h +1 -1
@@ -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);
virt/kvm/irq_comm.c +14 -8
@@ -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.
Gleb,
Don't you want IRQ ack notification instead to control reinjection?
Because I think you'll always see a successful injection if using PIC.
Quoted 5 lines · Gleb Natapov
include/linux/kvm.h +0
-0
include/linux/kvm.h struct kvm_irq_level { · line 56
Quoted 10 lines
include/linux/kvm.h +4
-1@@ -48,7 +48,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; };
And won't this break older userspace?
Quoted 4 lines · Marcelo Tosatti
Gleb,
Don't you want IRQ ack notification instead to control reinjection?
I don't see the easy way to do it. There are couple of ways to do what I need with IRQ ack notifications:
1) expose them to userspace. Each IRQ ack will generate VM exit.
2) make kernel to alway track particular IRQs (userspace will need to tell kernel which ones it wants to be tracked) and return status using this info instead of the way my patch does it.
3) Like above but re-inject interrupt from inside the kernel instead of reporting delivery status to userspace.
First one will generate more VM exist -> not good. The third one has problem with RTC frequency changes. So the only sane option is second one, but why us it if we can know if interrupt injection failed during injection itself?
Quoted 2 lines
Because I think you'll always see a successful injection if using PIC.
Then my patch has a bug. I'll recheck. It works for APIC.
Quoted 11 lines · Gleb Natapov
Quoted 10 lines
include/linux/kvm.h +0
-1@@ -48,7 +48,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;
Quoted 8 lines
include/linux/kvm.h struct kvm_irq_level { · line 56
Quoted 6 lines
include/linux/kvm.h +4
-0+union { +__u32 irq; +__s32 status; + };__u32 level; };And won't this break older userspace?
This should not since sizeof should remain the same. But my patch also changes ioctl definition and it will break old userspace for sure. To maintain backward compatibility I'll need to introduce new ioctl.
--
Gleb.
Quoted 2 lines · Marcelo Tosatti
Because I think you'll always see a successful injection if using PIC.
I've looked at the code one more time and I think that return value is correct for edge triggered interrupt. Injection of level triggered interrupt will always succeed as you say but this is more or less intentional. Device that uses level triggered interrupt can track interrupt status by itself since it controls IRQ line level. But I'll fix PIC code to return proper status anyway.
--
Gleb.