From patchwork Wed Aug 9 07:53:00 2017 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Elaine Zhang X-Patchwork-Id: 9889753 Return-Path: Received: from mail.wl.linuxfoundation.org (pdx-wl-mail.web.codeaurora.org [172.30.200.125]) by pdx-korg-patchwork.web.codeaurora.org (Postfix) with ESMTP id 49F2A60363 for ; Wed, 9 Aug 2017 07:48:44 +0000 (UTC) Received: from mail.wl.linuxfoundation.org (localhost [127.0.0.1]) by mail.wl.linuxfoundation.org (Postfix) with ESMTP id 3C2C528A2C for ; Wed, 9 Aug 2017 07:48:44 +0000 (UTC) Received: by mail.wl.linuxfoundation.org (Postfix, from userid 486) id 30F1528A32; Wed, 9 Aug 2017 07:48:44 +0000 (UTC) X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on pdx-wl-mail.web.codeaurora.org X-Spam-Level: X-Spam-Status: No, score=-1.9 required=2.0 tests=BAYES_00,DKIM_SIGNED, DKIM_VALID,RCVD_IN_DNSWL_NONE autolearn=unavailable version=3.3.1 Received: from bombadil.infradead.org (bombadil.infradead.org [65.50.211.133]) (using TLSv1.2 with cipher AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.wl.linuxfoundation.org (Postfix) with ESMTPS id D0B4B28A2C for ; Wed, 9 Aug 2017 07:48:43 +0000 (UTC) DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=lists.infradead.org; s=bombadil.20170209; h=Sender: Content-Transfer-Encoding:Content-Type:MIME-Version:Cc:List-Subscribe: List-Help:List-Post:List-Archive:List-Unsubscribe:List-Id:Message-Id:Date: Subject:To:From:Reply-To:Content-ID:Content-Description:Resent-Date: Resent-From:Resent-Sender:Resent-To:Resent-Cc:Resent-Message-ID:In-Reply-To: References:List-Owner; bh=P3vwH9wkXVL2OriSJMBEF0rn6IpZrco4SnQ1yh32268=; b=fBZ NfYzXBDMgDR2yX8WdGvDwNKu73ZJoavyxk+sTP3UHbtuGQ78YXkZvRG7FXt34MWyixhkaMMMwB5el n6ssltfzpdv0dxKVg01cobXP93AHlNnTX0v2K9XxoVwi3iPHDCTL74sQPN9/ghfVdzk+Zc8maN2Sv 8/S5AaPttRqDGh4pZzbS9pUULh5RJbOR4iVQxfVSlwCkEuVcoL0RxixwKW9oVWOTVnWbsMMZq0ykC wyXrFlW56bIQdTGXlQYrE6bizXy6T4w04WR18f1J6qIz66UeN3Ea4fIjip5cRG28aTeNZ/k/rsFUJ XTjqu0ShWtRwCSdnmZMvluzzOm2BKvA==; Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.87 #1 (Red Hat Linux)) id 1dfLjO-000332-PD; Wed, 09 Aug 2017 07:48:42 +0000 Received: from regular1.263xmail.com ([211.150.99.132]) by bombadil.infradead.org with esmtps (Exim 4.87 #1 (Red Hat Linux)) id 1dfLjL-00031T-Uo for linux-rockchip@lists.infradead.org; Wed, 09 Aug 2017 07:48:41 +0000 Received: from zhangqing?rock-chips.com (unknown [192.168.167.172]) by regular1.263xmail.com (Postfix) with ESMTP id AC39A94FF; Wed, 9 Aug 2017 15:48:14 +0800 (CST) X-263anti-spam: KSV:0; X-MAIL-GRAY: 0 X-MAIL-DELIVERY: 1 X-KSVirus-check: 0 X-ABS-CHECKED: 4 Received: from localhost.localdomain (localhost [127.0.0.1]) by smtp.263.net (Postfix) with ESMTPA id 775673AB; Wed, 9 Aug 2017 15:48:13 +0800 (CST) X-RL-SENDER: zhangqing@rock-chips.com X-FST-TO: mturquette@baylibre.com X-SENDER-IP: 58.22.7.114 X-LOGIN-NAME: zhangqing@rock-chips.com X-UNIQUE-TAG: X-ATTACHMENT-NUM: 0 X-SENDER: zhangqing@rock-chips.com X-DNS-TYPE: 0 Received: from localhost.localdomain (unknown [58.22.7.114]) by smtp.263.net (Postfix) whith ESMTP id 626F0KA22; Wed, 09 Aug 2017 15:48:15 +0800 (CST) From: Elaine Zhang To: mturquette@baylibre.com, sboyd@codeaurora.org, heiko@sntech.de Subject: [RESEND PATCH v1] clk: Keep clocks in their initial state until clk_disable_unused() is called Date: Wed, 9 Aug 2017 15:53:00 +0800 Message-Id: <1502265180-21661-1-git-send-email-zhangqing@rock-chips.com> X-Mailer: git-send-email 1.9.1 X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20170809_004840_363906_B4E573F3 X-CRM114-Status: GOOD ( 12.69 ) X-BeenThere: linux-rockchip@lists.infradead.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: Upstream kernel work for Rockchip platforms List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: huangtao@rock-chips.com, boris.brezillon@free-electrons.com, xf@rock-chips.com, xxx@rock-chips.com, Elaine Zhang , linux-kernel@vger.kernel.org, linux-rockchip@lists.infradead.org, xjq@rock-chips.com, david.wu@rock-chips.com, linux-clk@vger.kernel.org MIME-Version: 1.0 Sender: "Linux-rockchip" Errors-To: linux-rockchip-bounces+patchwork-linux-rockchip=patchwork.kernel.org@lists.infradead.org X-Virus-Scanned: ClamAV using ClamSMTP From: Boris Brezillon Some drivers are briefly preparing+enabling the clock in their ->probe() hook and disable+unprepare them before leaving the function. This can be problem if a clock is shared between different devices, and one of these devices is critical to the system. If this clock is enabled/disabled by a non-critical device before the driver of the critical one had a chance to enable+prepare it, there might be a short period of time during which the critical device is not clocked. To solve this problem, we save the initial clock state (at registration time) and prevent the clock from being disabled until kernel init is done (which is when clk_disable_unused() is called). Signed-off-by: Boris Brezillon Signed-off-by: Elaine Zhang --- drivers/clk/clk.c | 29 +++++++++++++++++++++++++++-- 1 file changed, 27 insertions(+), 2 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index fc58c52a26b4..3f61374a364b 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -58,6 +58,8 @@ struct clk_core { struct clk_core *new_child; unsigned long flags; bool orphan; + bool keep_enabled; + bool keep_prepared; unsigned int enable_count; unsigned int prepare_count; unsigned long min_rate; @@ -486,7 +488,7 @@ static void clk_core_unprepare(struct clk_core *core) trace_clk_unprepare(core); - if (core->ops->unprepare) + if (core->ops->unprepare && !core->keep_prepared) core->ops->unprepare(core->hw); trace_clk_unprepare_complete(core); @@ -602,7 +604,7 @@ static void clk_core_disable(struct clk_core *core) trace_clk_disable_rcuidle(core); - if (core->ops->disable) + if (core->ops->disable && !core->keep_enabled) core->ops->disable(core->hw); trace_clk_disable_complete_rcuidle(core); @@ -739,6 +741,12 @@ static void clk_unprepare_unused_subtree(struct clk_core *core) hlist_for_each_entry(child, &core->children, child_node) clk_unprepare_unused_subtree(child); + /* + * Reset the ->keep_prepared flag so that subsequent calls to + * clk_unprepare() on this clk actually unprepare it. + */ + core->keep_prepared = false; + if (core->prepare_count) return; @@ -770,6 +778,12 @@ static void clk_disable_unused_subtree(struct clk_core *core) flags = clk_enable_lock(); + /* + * Reset the ->keep_enabled flag so that subsequent calls to + * clk_disable() on this clk actually disable it. + */ + core->keep_enabled = false; + if (core->enable_count) goto unlock_out; @@ -2446,6 +2460,17 @@ static int __clk_core_init(struct clk_core *core) core->accuracy = 0; /* + * We keep track of the initial clk status to keep clks in the state + * they were left in by the bootloader until all drivers had a chance + * to keep them prepared/enabled if they need to. + */ + if (core->ops->is_prepared && !clk_ignore_unused) + core->keep_prepared = core->ops->is_prepared(core->hw); + + if (core->ops->is_enabled && !clk_ignore_unused) + core->keep_enabled = core->ops->is_enabled(core->hw); + + /* * Set clk's phase. * Since a phase is by definition relative to its parent, just * query the current clock phase, or just assume it's in phase.