From patchwork Mon Oct 22 13:15:21 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Linus Walleij X-Patchwork-Id: 12403 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 29B4C23EC8 for ; Mon, 22 Oct 2012 13:15:57 +0000 (UTC) Received: from mail-ie0-f180.google.com (mail-ie0-f180.google.com [209.85.223.180]) by fiordland.canonical.com (Postfix) with ESMTP id BC10FA19961 for ; Mon, 22 Oct 2012 13:15:56 +0000 (UTC) Received: by mail-ie0-f180.google.com with SMTP id e10so3385601iej.11 for ; Mon, 22 Oct 2012 06:15:56 -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=8yOTkF0hdBE3N8KyV73wo+i5kMxobEFADtHaP5Aitkk=; b=lHE86t7qF/TOCxifZ/BA+Y6EEqA2nrUPBArlKgw/XW9UxOL0nY5HrlgJXQqVj3Qh8l dH0KlrTJg3GlU51gVHB/CUvYa6SglX+pW4P+PqRdWzWwO3/waf7OVHaXQ46B9Xw9viiR xWiV3DiiHdS6V/mnNq+99SOsylYmRvgUmpFd0pqPkJUQH7CssRDGOfmZCa/e0xcQEagG rPpfNOA9BhftFfH0UWxU3+H3BEzU+94z2t+83GWwgy9f6h/07OSSefH2ZkISbpBVETqX UQUANJdwieG8qaho8gkmnL8FAacH7vt8POWEQ5+TOWBnu7e+qMJFgxOquMXSjRq4KnbA LaAA== Received: by 10.50.140.97 with SMTP id rf1mr14410399igb.70.1350911756098; Mon, 22 Oct 2012 06:15:56 -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 n20csp230468igt; Mon, 22 Oct 2012 06:15:55 -0700 (PDT) Received: by 10.14.214.2 with SMTP id b2mr12081182eep.32.1350911754647; Mon, 22 Oct 2012 06:15:54 -0700 (PDT) Received: from eu1sys200aog108.obsmtp.com (eu1sys200aog108.obsmtp.com [207.126.144.125]) by mx.google.com with SMTP id j5si6017020eeo.74.2012.10.22.06.15.47 (version=TLSv1/SSLv3 cipher=OTHER); Mon, 22 Oct 2012 06:15:54 -0700 (PDT) Received-SPF: neutral (google.com: 207.126.144.125 is neither permitted nor denied by best guess record for domain of linus.walleij@stericsson.com) client-ip=207.126.144.125; Authentication-Results: mx.google.com; spf=neutral (google.com: 207.126.144.125 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-us.st.com ([167.4.1.35]) (using TLSv1) by eu1sys200aob108.postini.com ([207.126.147.11]) with SMTP ID DSNKUIVHAGOLyJfe3QET9zOpBULtwFFMWrrD@postini.com; Mon, 22 Oct 2012 13:15:54 UTC Received: from zeta.dmz-us.st.com (ns4.st.com [167.4.16.71]) by beta.dmz-us.st.com (STMicroelectronics) with ESMTP id B5F013E; Mon, 22 Oct 2012 13:14:55 +0000 (GMT) Received: from relay1.stm.gmessaging.net (unknown [10.230.100.17]) by zeta.dmz-us.st.com (STMicroelectronics) with ESMTP id AA9426F; Mon, 22 Oct 2012 08:44:56 +0000 (GMT) Received: from exdcvycastm003.EQ1STM.local (alteon-source-exch [10.230.100.61]) (using TLSv1 with cipher RC4-MD5 (128/128 bits)) (Client CN "exdcvycastm003", Issuer "exdcvycastm003" (not verified)) by relay1.stm.gmessaging.net (Postfix) with ESMTPS id 8917424C07D; Mon, 22 Oct 2012 15:15:19 +0200 (CEST) Received: from steludxu4075.lud.stericsson.com (10.230.100.153) by smtp.stericsson.com (10.230.100.1) with Microsoft SMTP Server (TLS) id 8.3.83.0; Mon, 22 Oct 2012 15:15:26 +0200 From: Linus Walleij To: Russell King , Cc: Colin Cross , Thomas Gleixner , Santosh Shilimkar , Shiraz Hashim , Shawn Guo , Linus Walleij Subject: [PATCH v4] ARM: SMP_TWD: make setup()/stop() reentrant Date: Mon, 22 Oct 2012 15:15:21 +0200 Message-ID: <1350911721-3184-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: ALoCoQlkW0ZN4Hd6BDuQ6QgyuAfIr8nQKipdlmV6BZzhvz5IgqOvWargSiZs7IX52ezX2YcLMCNy 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 v3->v4: - Skip clk_enable()/clk_disable() in subsequent call after common initialization - there is no way we can turn off the clock that is running us anyway. - Move common_setup_called variable assignment into the if-clause --- arch/arm/kernel/smp_twd.c | 42 +++++++++++++++++++++++++++++++++++++----- 1 file changed, 37 insertions(+), 5 deletions(-) diff --git a/arch/arm/kernel/smp_twd.c b/arch/arm/kernel/smp_twd.c index b92d524..ff07879 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; @@ -264,15 +266,45 @@ 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)) { + __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";