From patchwork Sat Aug 6 10:40:15 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Christoffer Dall X-Patchwork-Id: 1047012 Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by demeter1.kernel.org (8.14.4/8.14.4) with ESMTP id p78LkCH9027838 for ; Mon, 8 Aug 2011 21:46:12 GMT Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1753134Ab1HHVqJ (ORCPT ); Mon, 8 Aug 2011 17:46:09 -0400 Received: from mail-fx0-f46.google.com ([209.85.161.46]:53863 "EHLO mail-fx0-f46.google.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1752879Ab1HHVqJ (ORCPT ); Mon, 8 Aug 2011 17:46:09 -0400 Received: by mail-fx0-f46.google.com with SMTP id 19so5784586fxh.19 for ; Mon, 08 Aug 2011 14:46:08 -0700 (PDT) Received: by 10.223.155.71 with SMTP id r7mr5313623faw.17.1312839968299; Mon, 08 Aug 2011 14:46:08 -0700 (PDT) Received: from localhost6.localdomain6 (h-165-152.a220.priv.bahnhof.se [81.170.165.152]) by mx.google.com with ESMTPS id o1sm2090017fah.24.2011.08.08.14.46.07 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 08 Aug 2011 14:46:07 -0700 (PDT) Subject: [PATCH v4 10/10] ARM: KVM: Guest wait-for-interrupts (WFI) support To: kvm@vger.kernel.org From: Christoffer Dall Cc: catalin.marinas@arm.com, tech@virtualopensystems.com, android-virt@lists.cs.columbia.edu Date: Sat, 06 Aug 2011 12:40:15 +0200 Message-ID: <20110806104015.27198.1042.stgit@localhost6.localdomain6> In-Reply-To: <20110806103821.27198.41231.stgit@localhost6.localdomain6> References: <20110806103821.27198.41231.stgit@localhost6.localdomain6> User-Agent: StGit/0.15 MIME-Version: 1.0 Sender: kvm-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm@vger.kernel.org X-Greylist: IP, sender and recipient auto-whitelisted, not delayed by milter-greylist-4.2.6 (demeter1.kernel.org [140.211.167.41]); Mon, 08 Aug 2011 21:46:13 +0000 (UTC) When the guest executes a WFI instruction the operation is trapped to KVM, which emulates the instruction in software. There is no correlation between a guest executing a WFI instruction and actually puttin the hardware into a low-power mode, since a KVM guest is essentially a process and the WFI instruction can be seen as 'sleep' call from this process. Therefore, we flag the VCPU to be in wait_for_interrupts mode and call the main KVM function kvm_vcpu_block() function. This function will put the thread on a wait-queue and call schedule. When an interrupt comes in through KVM_IRQ_LINE (see previous patch) we signal the VCPU thread and unflag the VCPU to no longer wait for interrupts. All calls to kvm_arch_vcpu_ioctl_run() result in a call to kvm_vcpu_block() as long as the VCPU is in wfi-mode. Signed-off-by: Christoffer Dall --- arch/arm/kvm/arm.c | 20 +++++++++++++++++++- arch/arm/kvm/arm_emulate.c | 11 +++++++++++ arch/arm/kvm/trace.h | 15 +++++++++++++++ 3 files changed, 45 insertions(+), 1 deletions(-) -- To unsubscribe from this list: send the line "unsubscribe kvm" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html diff --git a/arch/arm/kvm/arm.c b/arch/arm/kvm/arm.c index 3e3f6d7..693ba69 100644 --- a/arch/arm/kvm/arm.c +++ b/arch/arm/kvm/arm.c @@ -307,9 +307,18 @@ int kvm_arch_vcpu_ioctl_set_mpstate(struct kvm_vcpu *vcpu, return -EINVAL; } +/** + * kvm_arch_vcpu_runnable - determine if the vcpu can be scheduled + * @v: The VCPU pointer + * + * If the guest CPU is not waiting for interrupts (or is waiting for interrupts + * but there actually is an incoming interrupt), then it is by definition + * runnable. + */ int kvm_arch_vcpu_runnable(struct kvm_vcpu *v) { - return 0; + return !!v->arch.virt_irq || + !v->arch.wait_for_interrupts; } static inline int handle_exit(struct kvm_vcpu *vcpu, struct kvm_run *run, @@ -385,6 +394,9 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) int ret; for (;;) { + if (vcpu->arch.wait_for_interrupts) + goto wait_for_interrupts; + if (run->exit_reason == KVM_EXIT_MMIO) { ret = kvm_handle_mmio_return(vcpu, vcpu->run); if (ret) @@ -420,6 +432,10 @@ int kvm_arch_vcpu_ioctl_run(struct kvm_vcpu *vcpu, struct kvm_run *run) vcpu_load(vcpu); } +wait_for_interrupts: + if (vcpu->arch.wait_for_interrupts) + kvm_vcpu_block(vcpu); + if (signal_pending(current) && !(run->exit_reason)) { run->exit_reason = KVM_EXIT_IRQ_WINDOW_OPEN; break; @@ -460,6 +476,8 @@ static int kvm_arch_vm_ioctl_irq_line(struct kvm *kvm, if (irq_level->level) { vcpu->arch.virt_irq |= mask; vcpu->arch.wait_for_interrupts = 0; + if (waitqueue_active(&vcpu->wq)) + wake_up_interruptible(&vcpu->wq); } else vcpu->arch.virt_irq &= ~mask; diff --git a/arch/arm/kvm/arm_emulate.c b/arch/arm/kvm/arm_emulate.c index 0c99360..928c747 100644 --- a/arch/arm/kvm/arm_emulate.c +++ b/arch/arm/kvm/arm_emulate.c @@ -333,8 +333,19 @@ unsupp_err_out: return -EINVAL; } +/** + * kvm_handle_wfi - handle a wait-for-interrupts instruction executed by a guest + * @vcpu: the vcpu pointer + * @run: the kvm_run structure pointer + * + * Simply sets the wait_for_interrupts flag on the vcpu structure, which will + * halt execution of world-switches and schedule other host processes until + * there is an incoming IRQ or FIQ to the VM. + */ int kvm_handle_wfi(struct kvm_vcpu *vcpu, struct kvm_run *run) { + trace_kvm_wfi(vcpu->arch.regs.pc); + vcpu->arch.wait_for_interrupts = 1; return 0; } diff --git a/arch/arm/kvm/trace.h b/arch/arm/kvm/trace.h index 4f20d75..2ea01f5 100644 --- a/arch/arm/kvm/trace.h +++ b/arch/arm/kvm/trace.h @@ -104,6 +104,21 @@ TRACE_EVENT(kvm_irq_line, __entry->level, __entry->vcpu_idx) ); +TRACE_EVENT(kvm_wfi, + TP_PROTO(unsigned long vcpu_pc), + TP_ARGS(vcpu_pc), + + TP_STRUCT__entry( + __field( unsigned long, vcpu_pc ) + ), + + TP_fast_assign( + __entry->vcpu_pc = vcpu_pc; + ), + + TP_printk("guest executed wfi at: 0x%08lx", __entry->vcpu_pc) +); + #endif /* _TRACE_KVM_H */