From mboxrd@z Thu Jan 1 00:00:00 1970 From: Dor Laor Subject: [RFC][PATCH] Return interrupt acknoledge info to userspace Date: Sun, 23 Mar 2008 16:29:18 +0200 Message-ID: <1206282559.18800.34.camel@localhost.localdomain> Reply-To: dor.laor@qumranet.com Mime-Version: 1.0 Content-Type: multipart/mixed; boundary="=-53mlWhGIBcIE41NYYsp6" To: kvm-devel Return-path: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: kvm-devel-bounces@lists.sourceforge.net Errors-To: kvm-devel-bounces@lists.sourceforge.net List-Id: kvm.vger.kernel.org --=-53mlWhGIBcIE41NYYsp6 Content-Type: text/plain Content-Transfer-Encoding: 7bit User space device emulation for timers might be inaccurate and cause coalescing of several irq into one. It happens when the load on the host is high and the guest did not manage to ack the previous irq. By get/set request irq commands the device won't issue another irq before the previous one has been acknowledged. Userspace will request information about acking certain irq vectors. Every vcpu will update this information in its vcpu_run structure, it is in/out variable. Note that if there is pending irq that didn't manage to be injected, it is being cleared. Signed-off-by: Dor Laor --- arch/x86/kvm/svm.c | 1 + arch/x86/kvm/vmx.c | 1 + arch/x86/kvm/x86.c | 20 ++++++++++++++++++-- include/asm-x86/kvm_host.h | 2 ++ include/linux/kvm.h | 5 +++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 51741f9..41c680d 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1501,6 +1501,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) intr_vector = kvm_cpu_get_interrupt(vcpu); svm_inject_irq(svm, intr_vector); kvm_timer_intr_post(vcpu, intr_vector); + clear_bit(intr_vector, vcpu->arch.irq_ack_requests); } static void kvm_reput_irq(struct vcpu_svm *svm) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fb0389d..ab71433 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2369,6 +2369,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) vector = kvm_cpu_get_interrupt(vcpu); vmx_inject_irq(vcpu, vector); kvm_timer_intr_post(vcpu, vector); + clear_bit(vector, vcpu->arch.irq_ack_requests); } else enable_irq_window(vcpu); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 63afca1..d7733e9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2689,8 +2689,21 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu, kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; kvm_run->cr8 = kvm_get_cr8(vcpu); kvm_run->apic_base = kvm_get_apic_base(vcpu); - if (irqchip_in_kernel(vcpu->kvm)) + if (irqchip_in_kernel(vcpu->kvm)) { + int pending_vec; + kvm_run->ready_for_interrupt_injection = 1; + /* + * Sync userspace the acknoledge irqs that were requested, + * remove irqs that were not yet injected (pending) + */ + pending_vec = kvm_x86_ops->get_irq(vcpu); + if (pending_vec != -1 && + test_bit(pending_vec, kvm_run->irq_acked)) + set_bit(pending_vec, vcpu->arch.irq_ack_requests); + memcpy(kvm_run->irq_acked, vcpu->arch.irq_ack_requests, + sizeof(vcpu->arch.irq_ack_requests)); + } else kvm_run->ready_for_interrupt_injection = (vcpu->arch.interrupt_window_open && @@ -2891,9 +2904,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - /* re-sync apic's tpr */ if (!irqchip_in_kernel(vcpu->kvm)) + /* re-sync apic's tpr */ kvm_set_cr8(vcpu, kvm_run->cr8); + else + memcpy(vcpu->arch.irq_ack_requests, kvm_run->irq_acked, + sizeof(vcpu->arch.irq_ack_requests)); if (vcpu->arch.pio.cur_count) { r = complete_pio(vcpu); diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 2773f91..d839e43 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -213,6 +213,8 @@ struct kvm_vcpu_arch { int interrupt_window_open; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); + DECLARE_BITMAP(irq_ack_requests, KVM_NR_INTERRUPTS); + unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ unsigned long rip; /* needs vcpu_load_rsp_rip() */ diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 3bd3828..537d3f7 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -141,6 +141,11 @@ struct kvm_run { /* Fix the size of the union. */ char padding[256]; }; + +/* Max architectural interrupt line count. */ +#define MAX_KVM_NR_INTERRUPTS 256 + /* in (pre_kvm_run), out (post_kvm_run) */ + __u64 irq_acked[(MAX_KVM_NR_INTERRUPTS + 63) / 64]; }; /* for KVM_TRANSLATE */ -- 1.5.4.1 --=-53mlWhGIBcIE41NYYsp6 Content-Disposition: attachment; filename=0001-KVM-Return-interrupt-acknoledge-info-to-userspace.patch Content-Type: application/mbox; name=0001-KVM-Return-interrupt-acknoledge-info-to-userspace.patch Content-Transfer-Encoding: 7bit >>From c76378355d5478f89971b2fa8053a1891a503af6 Mon Sep 17 00:00:00 2001 From: Dor Laor Date: Sun, 23 Mar 2008 15:20:49 +0200 Subject: [PATCH] [KVM] Return interrupt acknoledge info to userspace User space device emulation for timers might be inaccurate and ause coalescing of several irq into one. It happens when the load on the host is high and the guest did not manage to ack the previous irq. By get/set request irq commands the device won't issue another irq before the previous one has been acknoledged. Userspace will request information about acking certain irq vectors. Every vcpu will update this information in its vcpu_run structure, it is in/out variable. Note that if there is pending irq that didn't manage to be injected, it is being cleared. Signed-off-by: Dor Laor --- arch/x86/kvm/svm.c | 1 + arch/x86/kvm/vmx.c | 1 + arch/x86/kvm/x86.c | 20 ++++++++++++++++++-- include/asm-x86/kvm_host.h | 2 ++ include/linux/kvm.h | 5 +++++ 5 files changed, 27 insertions(+), 2 deletions(-) diff --git a/arch/x86/kvm/svm.c b/arch/x86/kvm/svm.c index 51741f9..41c680d 100644 --- a/arch/x86/kvm/svm.c +++ b/arch/x86/kvm/svm.c @@ -1501,6 +1501,7 @@ static void svm_intr_assist(struct kvm_vcpu *vcpu) intr_vector = kvm_cpu_get_interrupt(vcpu); svm_inject_irq(svm, intr_vector); kvm_timer_intr_post(vcpu, intr_vector); + clear_bit(intr_vector, vcpu->arch.irq_ack_requests); } static void kvm_reput_irq(struct vcpu_svm *svm) diff --git a/arch/x86/kvm/vmx.c b/arch/x86/kvm/vmx.c index fb0389d..ab71433 100644 --- a/arch/x86/kvm/vmx.c +++ b/arch/x86/kvm/vmx.c @@ -2369,6 +2369,7 @@ static void vmx_intr_assist(struct kvm_vcpu *vcpu) vector = kvm_cpu_get_interrupt(vcpu); vmx_inject_irq(vcpu, vector); kvm_timer_intr_post(vcpu, vector); + clear_bit(vector, vcpu->arch.irq_ack_requests); } else enable_irq_window(vcpu); } diff --git a/arch/x86/kvm/x86.c b/arch/x86/kvm/x86.c index 63afca1..d7733e9 100644 --- a/arch/x86/kvm/x86.c +++ b/arch/x86/kvm/x86.c @@ -2689,8 +2689,21 @@ static void post_kvm_run_save(struct kvm_vcpu *vcpu, kvm_run->if_flag = (kvm_x86_ops->get_rflags(vcpu) & X86_EFLAGS_IF) != 0; kvm_run->cr8 = kvm_get_cr8(vcpu); kvm_run->apic_base = kvm_get_apic_base(vcpu); - if (irqchip_in_kernel(vcpu->kvm)) + if (irqchip_in_kernel(vcpu->kvm)) { + int pending_vec; + kvm_run->ready_for_interrupt_injection = 1; + /* + * Sync userspace the acknoledge irqs that were requested, + * remove irqs that were not yet injected (pending) + */ + pending_vec = kvm_x86_ops->get_irq(vcpu); + if (pending_vec != -1 && + test_bit(pending_vec, kvm_run->irq_acked)) + set_bit(pending_vec, vcpu->arch.irq_ack_requests); + memcpy(kvm_run->irq_acked, vcpu->arch.irq_ack_requests, + sizeof(vcpu->arch.irq_ack_requests)); + } else kvm_run->ready_for_interrupt_injection = (vcpu->arch.interrupt_window_open && @@ -2891,9 +2904,12 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *kvm_run) if (vcpu->sigset_active) sigprocmask(SIG_SETMASK, &vcpu->sigset, &sigsaved); - /* re-sync apic's tpr */ if (!irqchip_in_kernel(vcpu->kvm)) + /* re-sync apic's tpr */ kvm_set_cr8(vcpu, kvm_run->cr8); + else + memcpy(vcpu->arch.irq_ack_requests, kvm_run->irq_acked, + sizeof(vcpu->arch.irq_ack_requests)); if (vcpu->arch.pio.cur_count) { r = complete_pio(vcpu); diff --git a/include/asm-x86/kvm_host.h b/include/asm-x86/kvm_host.h index 2773f91..d839e43 100644 --- a/include/asm-x86/kvm_host.h +++ b/include/asm-x86/kvm_host.h @@ -213,6 +213,8 @@ struct kvm_vcpu_arch { int interrupt_window_open; unsigned long irq_summary; /* bit vector: 1 per word in irq_pending */ DECLARE_BITMAP(irq_pending, KVM_NR_INTERRUPTS); + DECLARE_BITMAP(irq_ack_requests, KVM_NR_INTERRUPTS); + unsigned long regs[NR_VCPU_REGS]; /* for rsp: vcpu_load_rsp_rip() */ unsigned long rip; /* needs vcpu_load_rsp_rip() */ diff --git a/include/linux/kvm.h b/include/linux/kvm.h index 3bd3828..537d3f7 100644 --- a/include/linux/kvm.h +++ b/include/linux/kvm.h @@ -141,6 +141,11 @@ struct kvm_run { /* Fix the size of the union. */ char padding[256]; }; + +/* Max architectural interrupt line count. */ +#define MAX_KVM_NR_INTERRUPTS 256 + /* in (pre_kvm_run), out (post_kvm_run) */ + __u64 irq_acked[(MAX_KVM_NR_INTERRUPTS + 63) / 64]; }; /* for KVM_TRANSLATE */ -- 1.5.4.1 --=-53mlWhGIBcIE41NYYsp6 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline ------------------------------------------------------------------------- This SF.net email is sponsored by: Microsoft Defy all challenges. Microsoft(R) Visual Studio 2008. http://clk.atdmt.com/MRT/go/vse0120000070mrt/direct/01/ --=-53mlWhGIBcIE41NYYsp6 Content-Type: text/plain; charset="us-ascii" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit Content-Disposition: inline _______________________________________________ kvm-devel mailing list kvm-devel@lists.sourceforge.net https://lists.sourceforge.net/lists/listinfo/kvm-devel --=-53mlWhGIBcIE41NYYsp6--