From patchwork Thu Apr 26 10:19:03 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Alexander Graf X-Patchwork-Id: 155229 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by ozlabs.org (Postfix) with ESMTP id 2A6CEB6FA5 for ; Thu, 26 Apr 2012 20:19:54 +1000 (EST) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1756042Ab2DZKTJ (ORCPT ); Thu, 26 Apr 2012 06:19:09 -0400 Received: from cantor2.suse.de ([195.135.220.15]:56709 "EHLO mx2.suse.de" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1755893Ab2DZKTE (ORCPT ); Thu, 26 Apr 2012 06:19:04 -0400 Received: from relay1.suse.de (unknown [195.135.220.254]) (using TLSv1 with cipher DHE-RSA-AES256-SHA (256/256 bits)) (No client certificate requested) by mx2.suse.de (Postfix) with ESMTP id EABCE9EEF9; Thu, 26 Apr 2012 12:19:03 +0200 (CEST) From: Alexander Graf To: kvm list Cc: kvm-ppc , Benjamin Herrenschmidt Subject: [PATCH 2/2] KVM: PPC: Book3S: Call into C interrupt handlers Date: Thu, 26 Apr 2012 12:19:03 +0200 Message-Id: <1335435543-19690-2-git-send-email-agraf@suse.de> X-Mailer: git-send-email 1.6.0.2 In-Reply-To: <1335435543-19690-1-git-send-email-agraf@suse.de> References: <1335435543-19690-1-git-send-email-agraf@suse.de> Sender: kvm-ppc-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: kvm-ppc@vger.kernel.org Some interrupts only should be deferred when intercepted by KVM code, not completely handled by KVM. Thus we need to call into Linux' interrupt handling code for a few vectors. So far, this has been done by calling right back into the original interrupt vector once we're far enough in the guest exit code path. However, this adds more code to be executed, because we need to save and restore more state during the full interrupt cycle. We also lose out on compiler optimizations, since it's all hand written asm. So switch the code over to call into the Linux C handlers from C code, speeding up everything along the way. Along the way, this fixes a bug where we would have to set HSSR instead of SSR SPRs for the interrupt vector, making hv capable hosts work again properly. Signed-off-by: Alexander Graf --- arch/powerpc/kvm/book3s_pr.c | 58 +++++++++++++++++++++++++++++++++++++ arch/powerpc/kvm/book3s_segment.S | 25 +--------------- 2 files changed, 59 insertions(+), 24 deletions(-) diff --git a/arch/powerpc/kvm/book3s_pr.c b/arch/powerpc/kvm/book3s_pr.c index dba282e..f84b7ba 100644 --- a/arch/powerpc/kvm/book3s_pr.c +++ b/arch/powerpc/kvm/book3s_pr.c @@ -54,6 +54,11 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, #define HW_PAGE_SIZE PAGE_SIZE #define __hard_irq_disable local_irq_disable #define __hard_irq_enable local_irq_enable +static void soft_irq_disable(void) { } +static void soft_irq_enable(void) { } +#else +#define soft_irq_disable local_irq_disable +#define soft_irq_enable local_irq_enable #endif void kvmppc_core_vcpu_load(struct kvm_vcpu *vcpu, int cpu) @@ -538,6 +543,55 @@ static int kvmppc_handle_ext(struct kvm_vcpu *vcpu, unsigned int exit_nr, return RESUME_GUEST; } +static void kvmppc_fill_pt_regs(struct pt_regs *regs) +{ + ulong r1, ip, msr, lr; + + asm("mr %0, 1" : "=r"(r1)); + asm("mflr %0" : "=r"(lr)); + asm("mfmsr %0" : "=r"(msr)); + asm("bl 1f; 1: mflr %0" : "=r"(ip)); + + memset(regs, 0, sizeof(*regs)); + regs->gpr[1] = r1; + regs->nip = ip; + regs->msr = msr; + regs->link = lr; +} + +static void kvmppc_restart_interrupt(struct kvm_vcpu *vcpu, + unsigned int exit_nr) +{ + struct pt_regs regs; + + switch (exit_nr) { + case BOOK3S_INTERRUPT_EXTERNAL: + case BOOK3S_INTERRUPT_EXTERNAL_LEVEL: + case BOOK3S_INTERRUPT_EXTERNAL_HV: + kvmppc_fill_pt_regs(®s); + soft_irq_disable(); + do_IRQ(®s); + soft_irq_enable(); + break; + case BOOK3S_INTERRUPT_DECREMENTER: + case BOOK3S_INTERRUPT_HV_DECREMENTER: + kvmppc_fill_pt_regs(®s); + soft_irq_disable(); + timer_interrupt(®s); + soft_irq_enable(); + break; + case BOOK3S_INTERRUPT_MACHINE_CHECK: + /* FIXME */ + break; + case BOOK3S_INTERRUPT_PERFMON: + kvmppc_fill_pt_regs(®s); + soft_irq_disable(); + performance_monitor_exception(®s); + soft_irq_enable(); + break; + } +} + int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, unsigned int exit_nr) { @@ -548,6 +602,10 @@ int kvmppc_handle_exit(struct kvm_run *run, struct kvm_vcpu *vcpu, run->exit_reason = KVM_EXIT_UNKNOWN; run->ready_for_interrupt_injection = 1; + /* restart interrupts if they were meant for the host */ + kvmppc_restart_interrupt(vcpu, exit_nr); + __hard_irq_enable(); + trace_kvm_book3s_exit(exit_nr, vcpu); preempt_enable(); kvm_resched(vcpu); diff --git a/arch/powerpc/kvm/book3s_segment.S b/arch/powerpc/kvm/book3s_segment.S index 6bae0a9..3a78b46 100644 --- a/arch/powerpc/kvm/book3s_segment.S +++ b/arch/powerpc/kvm/book3s_segment.S @@ -308,28 +308,6 @@ no_dcbz32_off: #endif /* CONFIG_PPC_BOOK3S_64 */ - /* - * For some interrupts, we need to call the real Linux - * handler, so it can do work for us. This has to happen - * as if the interrupt arrived from the kernel though, - * so let's fake it here where most state is restored. - * - * Having set up SRR0/1 with the address where we want - * to continue with relocation on (potentially in module - * space), we either just go straight there with rfi[d], - * or we jump to an interrupt handler with bctr if there - * is an interrupt to be handled first. In the latter - * case, the rfi[d] at the end of the interrupt handler - * will get us back to where we want to continue. - */ - - cmpwi r12, BOOK3S_INTERRUPT_EXTERNAL - beq 1f - cmpwi r12, BOOK3S_INTERRUPT_DECREMENTER - beq 1f - cmpwi r12, BOOK3S_INTERRUPT_PERFMON -1: mtctr r12 - /* Register usage at this point: * * R1 = host R1 @@ -348,7 +326,6 @@ no_dcbz32_off: /* Load highmem handler address */ mtsrr0 r8 - /* RFI into the highmem handler, or jump to interrupt handler */ - beqctr + /* RFI into the highmem handler */ RFI kvmppc_handler_trampoline_exit_end: