From patchwork Mon Oct 22 10:10:49 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 12391 Return-Path: X-Original-To: patchwork@peony.canonical.com Delivered-To: patchwork@peony.canonical.com Received: from fiordland.canonical.com (fiordland.canonical.com [91.189.94.145]) by peony.canonical.com (Postfix) with ESMTP id 281E623E01 for ; Mon, 22 Oct 2012 10:11:27 +0000 (UTC) Received: from mail-ia0-f180.google.com (mail-ia0-f180.google.com [209.85.210.180]) by fiordland.canonical.com (Postfix) with ESMTP id 9A89FA198C9 for ; Mon, 22 Oct 2012 10:11:26 +0000 (UTC) Received: by mail-ia0-f180.google.com with SMTP id f6so1859556iag.11 for ; Mon, 22 Oct 2012 03:11:26 -0700 (PDT) X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=20120113; h=x-forwarded-to:x-forwarded-for:delivered-to:received-spf:from:to:cc :subject:date:message-id:x-mailer:mime-version:content-type :x-gm-message-state; bh=kAOKDwzHHchvAykI7bL90AsdwMwXsKP/kgsk1cgVyMY=; b=F8Ts06l03kBUi8InfIlzwIKlZhsALr7V6LErHjXmeVi7tIpLWRqdU6OVB8cl1Oqq7C ZCvAbEam2MOsJX+SIBo0HMIugvt6XlwYn5zkVoToOAXvyTdo4COgpAjQrEV61++YgMAI aOGqx6Np9Ii0j05FA1KvsnE45F0prqx1PWbJ2XZatE/XXC2LU2nq2LZaDpcGjRuZDKO2 a9OdXDMkFXbp58xMwaaMzp3PKFtPR8E1D69K9MIpWgqFzKv0hNRLOuyMj/ulNJaH1Qum qZ0xxwjNxS3ZCLJPFkPHmU26Q8KrhoZYFsHGTiytCFKG5D2Ae6Hkv7txSbd27aOhy5DZ pIdA== Received: by 10.50.100.137 with SMTP id ey9mr8508971igb.57.1350900685983; Mon, 22 Oct 2012 03:11:25 -0700 (PDT) X-Forwarded-To: linaro-patchwork@canonical.com X-Forwarded-For: patch@linaro.org linaro-patchwork@canonical.com Delivered-To: patches@linaro.org Received: by 10.50.67.148 with SMTP id n20csp200624igt; Mon, 22 Oct 2012 03:11:25 -0700 (PDT) Received: by 10.14.1.69 with SMTP id 45mr11341497eec.23.1350900684328; Mon, 22 Oct 2012 03:11:24 -0700 (PDT) Received: from eu1sys200aog112.obsmtp.com (eu1sys200aog112.obsmtp.com [207.126.144.133]) by mx.google.com with SMTP id e6si2612040eem.12.2012.10.22.03.11.16 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 22 Oct 2012 03:11:24 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.133 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.133; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.133 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) smtp.mail=linus.walleij@stericsson.com Received: from beta.dmz-eu.st.com ([164.129.1.35]) (using TLSv1) by eu1sys200aob112.postini.com ([207.126.147.11]) with SMTP ID DSNKUIUbwBjR4dM6gT8rLW0jLLroUKikP0JJ@postini.com; Mon, 22 Oct 2012 10:11:24 UTC Received: from zeta.dmz-eu.st.com (zeta.dmz-eu.st.com [164.129.230.9]) by beta.dmz-eu.st.com (STMicroelectronics) with ESMTP id D2CE510E; Mon, 22 Oct 2012 10:10:56 +0000 (GMT) Received: from relay2.stm.gmessaging.net (unknown [10.230.100.18]) by zeta.dmz-eu.st.com (STMicroelectronics) with ESMTP id 0715B2AAD; Mon, 22 Oct 2012 10:10:55 +0000 (GMT) Received: from exdcvycastm004.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm004", Issuer "exdcvycastm004" (not verified)) by relay2.stm.gmessaging.net (Postfix) with ESMTPS id 3B3A9A8088; Mon, 22 Oct 2012 12:10:51 +0200 (CEST) Received: from steludxu4075.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.2) with Microsoft SMTP Server (TLS) id 8.3.83.0; Mon, 22 Oct 2012 12:10:55 +0200 From: Linus Walleij To: Russell King , Cc: Colin Cross , Thomas Gleixner , Santosh Shilimkar , Shiraz Hashim , Shawn Guo , Linus Walleij Subject: [PATCH v3] ARM: SMP_TWD: make setup()/stop() reentrant Date: Mon, 22 Oct 2012 12:10:49 +0200 Message-ID: <1350900649-25369-1-git-send-email-linus.walleij@stericsson.com> X-Mailer: git-send-email 1.7.11.3 MIME-Version: 1.0 X-Gm-Message-State: ALoCoQkJbhxA2ez1x9Yrvh/9I/V4y+/vNr4ntvYEidE3L7UGGl4AtlWVGXtU7hJDHLT4m4DqV/4A From: Linus Walleij It has been brought to my knowledge that the .setup()/.stop() function pair in the SMP TWD is going to be called from atomic contexts for CPUs coming and going, and then the clk_prepare()/clk_unprepare() calls cannot be called on subsequent .setup()/.stop() iterations. This is however just the tip of an iceberg as the function pair is not designed to be reentrant at all. This change makes the SMP_TWD clock .setup()/.stop() pair reentrant by splitting the .setup() function in three parts: - One COMMON part that is executed the first time the first CPU in the TWD cluster is initialized. This will fetch the TWD clk for the cluster and prepare+enable it. If no clk is available it will calibrate the rate instead. - One part that is executed the FIRST TIME a certain CPU is brought on-line. This initializes and sets up the clock event for a certain CPU. - One part that is executed on every subsequent .setup() call. This will re-initialize the clock event. This is augmented to call the clk_enable()/clk_disable() pair properly. Cc: Shawn Guo Reported-by: Peter Chen Signed-off-by: Linus Walleij --- ChangeLog v2->v3: - Split setup() in three parts - re-register the clock event on every setup() --- arch/arm/kernel/smp_twd.c | 45 ++++++++++++++++++++++++++++++++++++++++----- 1 file changed, 40 insertions(+), 5 deletions(-) diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index b92d524..73e25e2 100644 --- a/arch/arm/kernel/smp_twd.c +++ b/arch/arm/kernel/smp_twd.c @@ -31,6 +31,8 @@ static void __iomem *twd_base; static struct clk *twd_clk; static unsigned long twd_timer_rate; +static bool common_setup_called; +static DEFINE_PER_CPU(bool, percpu_setup_called); static struct clock_event_device __percpu **twd_evt; static int twd_ppi; @@ -93,6 +95,8 @@ static void twd_timer_stop(struct clock_event_device *clk) { twd_set_mode(CLOCK_EVT_MODE_UNUSED, clk); disable_percpu_irq(clk->irq); + if (!IS_ERR(twd_clk)) + clk_disable(twd_clk); } #ifdef CONFIG_COMMON_CLK @@ -264,15 +268,46 @@ static struct clk *twd_get_clock(void) static int __cpuinit twd_timer_setup(struct clock_event_device *clk) { struct clock_event_device **this_cpu_clk; + int cpu = smp_processor_id(); - if (!twd_clk) + /* + * If the basic setup for this CPU has been done before don't + * bother with the below. + */ + if (per_cpu(percpu_setup_called, cpu)) { + if (!IS_ERR(twd_clk)) + clk_enable(twd_clk); + __raw_writel(0, twd_base + TWD_TIMER_CONTROL); + clockevents_register_device(*__this_cpu_ptr(twd_evt)); + enable_percpu_irq(clk->irq, 0); + return 0; + } + per_cpu(percpu_setup_called, cpu) = true; + + /* + * This stuff only need to be done once for the entire TWD cluster + * during the runtime of the system. + */ + if (!common_setup_called) { twd_clk = twd_get_clock(); - if (!IS_ERR_OR_NULL(twd_clk)) - twd_timer_rate = clk_get_rate(twd_clk); - else - twd_calibrate_rate(); + /* + * We use IS_ERR_OR_NULL() here, because if the clock stubs + * are active we will get a valid clk reference which is + * however NULL and will return the rate 0. In that case we + * need to calibrate the rate instead. + */ + if (!IS_ERR_OR_NULL(twd_clk)) + twd_timer_rate = clk_get_rate(twd_clk); + else + twd_calibrate_rate(); + } + common_setup_called = true; + /* + * The following is done once per CPU the first time .setup() is + * called. + */ __raw_writel(0, twd_base + TWD_TIMER_CONTROL); clk->name = "local_timer";