From patchwork Fri Jul 6 09:20:22 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Marc Zyngier X-Patchwork-Id: 1164051 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 729F4DF236 for ; Fri, 6 Jul 2012 09:27:49 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Sn4jf-0003U0-3H; Fri, 06 Jul 2012 09:21:59 +0000 Received: from [91.220.42.44] (helo=service87.mimecast.com) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1Sn4ik-0003Lb-Oa for linux-arm-kernel@lists.infradead.org; Fri, 06 Jul 2012 09:21:07 +0000 Received: from cam-owa1.Emea.Arm.com (fw-tnat.cambridge.arm.com [217.140.96.21]) by service87.mimecast.com; Fri, 06 Jul 2012 10:20:27 +0100 Received: from e102391-lin.cambridge.arm.com ([10.1.255.212]) by cam-owa1.Emea.Arm.com with Microsoft SMTPSVC(6.0.3790.0); Fri, 6 Jul 2012 10:21:27 +0100 From: Marc Zyngier To: linux-arm-kernel@lists.infradead.org Subject: [RFC PATCH 4/4] ARM: arch_timers: dynamic switch to physical timer and virtual timer offloading Date: Fri, 6 Jul 2012 10:20:22 +0100 Message-Id: <1341566422-20368-5-git-send-email-marc.zyngier@arm.com> X-Mailer: git-send-email 1.7.10.3 In-Reply-To: <1341566422-20368-1-git-send-email-marc.zyngier@arm.com> References: <1341566422-20368-1-git-send-email-marc.zyngier@arm.com> X-OriginalArrivalTime: 06 Jul 2012 09:21:27.0310 (UTC) FILETIME=[B86E52E0:01CD5B58] X-MC-Unique: 112070610202708401 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -1.8 (-) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-1.8 points) pts rule name description ---- ---------------------- -------------------------------------------------- -0.7 RCVD_IN_DNSWL_LOW RBL: Sender listed at http://www.dnswl.org/, low trust [91.220.42.44 listed in list.dnswl.org] -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] 0.8 RDNS_NONE Delivered to internal network by a host with no rDNS X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org In an environment supporting virtualization (KVM), the virtual timer is reserved to the guests, while we rely on the physical timer for the host. For this, we need to: - switch the host CPUs from the virtual timer to the physical one - provide an interrupt handler that is called by the virtual timer's interrupt handler. The new function arch_timer_switch_to_phys() performs this task. Signed-off-by: Marc Zyngier --- arch/arm/include/asm/arch_timer.h | 6 +++++ arch/arm/kernel/arch_timer.c | 49 +++++++++++++++++++++++++++++++++++++ 2 files changed, 55 insertions(+) diff --git a/arch/arm/include/asm/arch_timer.h b/arch/arm/include/asm/arch_timer.h index 72c6822..7cd1e27 100644 --- a/arch/arm/include/asm/arch_timer.h +++ b/arch/arm/include/asm/arch_timer.h @@ -2,11 +2,13 @@ #define __ASMARM_ARCH_TIMER_H #include +#include #ifdef CONFIG_ARM_ARCH_TIMER int arch_timer_of_register(void); int arch_timer_sched_clock_init(void); struct timecounter *arch_timer_get_timecounter(void); +void arch_timer_switch_to_phys(irq_handler_t); #else static inline int arch_timer_of_register(void) { @@ -22,6 +24,10 @@ static inline struct timecounter *arch_timer_get_timecounter(void) { return NULL; } + +static inline void arch_timer_switch_to_phys(irq_handler_t handler) +{ +} #endif #endif diff --git a/arch/arm/kernel/arch_timer.c b/arch/arm/kernel/arch_timer.c index 4473f66..1bb632a 100644 --- a/arch/arm/kernel/arch_timer.c +++ b/arch/arm/kernel/arch_timer.c @@ -50,6 +50,8 @@ struct arch_timer_reg_ops { static struct arch_timer_reg_ops __percpu **arch_timer_reg_ops; +static irq_handler_t arch_timer_virt_external_handler; + /* * Architected system timer support. */ @@ -204,6 +206,19 @@ static irqreturn_t arch_timer_handler(int irq, void *dev_id) static irqreturn_t arch_timer_virt_handler(int irq, void *dev_id) { + if (arch_timer_virt_external_handler) { + unsigned long ctrl; + + ctrl = arch_timer_virt_reg_read(ARCH_TIMER_REG_CTRL); + if (ctrl & ARCH_TIMER_CTRL_IT_STAT) { + ctrl |= ARCH_TIMER_CTRL_IT_MASK; + arch_timer_virt_reg_write(ARCH_TIMER_REG_CTRL, ctrl); + return arch_timer_virt_external_handler(irq, NULL); + } + + return IRQ_NONE; + } + return arch_timer_handler(irq, dev_id); } @@ -509,3 +524,37 @@ int __init arch_timer_sched_clock_init(void) setup_sched_clock(arch_counter_get_cnt32, 32, arch_timer_rate); return 0; } + +static void arch_timer_switch_cpu_to_phys(void *dummy) +{ + u32 cvall, cvalh, val; + + pr_info("Switching CPU%d to physical timer\n", smp_processor_id()); + + asm volatile("mrrc p15, 3, %0, %1, c14 \n" /* Read CNTV_CVAL */ + "mcrr p15, 2, %0, %1, c14 \n" /* Write CNTP_CVAL */ + : "=r" (cvall), "=r" (cvalh)); + + isb(); + + val = arch_timer_virt_reg_read(ARCH_TIMER_REG_CTRL); + arch_timer_virt_reg_write(ARCH_TIMER_REG_CTRL, + val & ~ARCH_TIMER_CTRL_ENABLE); + arch_timer_phys_reg_write(ARCH_TIMER_REG_CTRL, val); + *__this_cpu_ptr(arch_timer_reg_ops) = &arch_timer_phys_ops; +} + +void arch_timer_switch_to_phys(irq_handler_t handler) +{ + int cpu; + + if (!arch_timer_use_virtual) + return; + + for_each_online_cpu(cpu) + smp_call_function_single(cpu, arch_timer_switch_cpu_to_phys, + NULL, 1); + + arch_timer_use_virtual = false; + arch_timer_virt_external_handler = handler; +}