From patchwork Mon Sep 22 14:15:48 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomeu Vizoso X-Patchwork-Id: 4948031 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.19.201]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 44A359F2BB for ; Mon, 22 Sep 2014 14:18:58 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id E0B9F201FA for ; Mon, 22 Sep 2014 14:18:56 +0000 (UTC) Received: from bombadil.infradead.org (bombadil.infradead.org [198.137.202.9]) (using TLSv1.2 with cipher DHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by mail.kernel.org (Postfix) with ESMTPS id 125E420121 for ; Mon, 22 Sep 2014 14:18:52 +0000 (UTC) Received: from localhost ([127.0.0.1] helo=bombadil.infradead.org) by bombadil.infradead.org with esmtp (Exim 4.80.1 #2 (Red Hat Linux)) id 1XW4Pz-0000sJ-5D; Mon, 22 Sep 2014 14:16:43 +0000 Received: from mail-we0-x235.google.com ([2a00:1450:400c:c03::235]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XW4Pw-0000iE-39 for linux-arm-kernel@lists.infradead.org; Mon, 22 Sep 2014 14:16:41 +0000 Received: by mail-we0-f181.google.com with SMTP id w61so1119092wes.40 for ; Mon, 22 Sep 2014 07:16:18 -0700 (PDT) DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20120113; h=sender:from:to:cc:subject:date:message-id:in-reply-to:references; bh=XoeI91P71eiIPHE7wfNvV/QWpaA8i+u/GuLyEpQlokI=; b=RKBplAWJubc8kofUtv5qnG4oC7FKsGRrlpoZypbUYSDHpGZOhHIw5hjdjGfjovqCCF sTrG+VjjKyMbi3VMsecSi+HGpbsIIIBLp9xCszKF2hnJgTE0wIObjuKylHU/pKhW1rWl SmuzWiPA41pVHxFPeAq2petkB2LsIMMCptfyGwb9pnfXlbMKRYW05qIr7ZLH7R0KDpzd sS2325I7DWid2JjPSpB/nwy74kqEa5e6u3gju0Y2wV7hU1miBy8AmblPw+Ctij8bhwa0 p5hbygFV6QbH60TMo+ooJBOyt7VCjDqSVNeN5EUEIdYcpQoqxwXhZK7XgMLIO6Mq6KLr ngcQ== X-Received: by 10.180.88.1 with SMTP id bc1mr15842495wib.45.1411395378057; Mon, 22 Sep 2014 07:16:18 -0700 (PDT) Received: from cizrna.lan (37-48-36-100.tmcz.cz. [37.48.36.100]) by mx.google.com with ESMTPSA id t9sm12442274wjf.41.2014.09.22.07.16.15 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Mon, 22 Sep 2014 07:16:17 -0700 (PDT) From: Tomeu Vizoso To: Mike Turquette Subject: [PATCH v12 05/10] clk: per-user clock accounting for debug Date: Mon, 22 Sep 2014 16:15:48 +0200 Message-Id: <1411395353-3189-2-git-send-email-tomeu.vizoso@collabora.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1411395353-3189-1-git-send-email-tomeu.vizoso@collabora.com> References: <1411395124-2476-1-git-send-email-tomeu.vizoso@collabora.com> <1411395353-3189-1-git-send-email-tomeu.vizoso@collabora.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140922_071640_463289_6FC1E222 X-CRM114-Status: GOOD ( 16.67 ) X-Spam-Score: -0.7 (/) Cc: Tomeu Vizoso , Stephen Warren , Peter De Schrijver , linux-kernel@vger.kernel.org, tomasz.figa@gmail.com, rabin@rab.in, Thierry Reding , Javier Martinez Canillas , linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.18-1 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , MIME-Version: 1.0 Sender: "linux-arm-kernel" Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org X-Spam-Status: No, score=-2.8 required=5.0 tests=BAYES_00,DKIM_SIGNED, RCVD_IN_DNSWL_NONE,RP_MATCHES_RCVD,T_DKIM_INVALID,UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP When a clock has multiple users, the WARNING on imbalance of enable/disable may not show the guilty party since although they may have commited the error earlier, the warning is emitted later when some other user, presumably innocent, disables the clock. Provide per-user clock enable/disable accounting and disabler tracking in order to help debug these problems. Based on previous work by Rabin Vincent . Signed-off-by: Tomeu Vizoso Tested-by: Heiko Stuebner --- drivers/clk/clk.c | 38 ++++++++++++++++++++++++++++++++++---- drivers/clk/clk.h | 3 ++- drivers/clk/clkdev.c | 14 ++++++++++---- include/linux/clk-private.h | 5 +++++ 4 files changed, 51 insertions(+), 9 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index 4fe67b8..5658bf4 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -543,7 +543,8 @@ static int clk_disable_unused(void) } late_initcall_sync(clk_disable_unused); -struct clk *__clk_create_clk(struct clk_core *clk_core) +struct clk *__clk_create_clk(struct clk_core *clk_core, const char *dev, + const char *con) { struct clk *clk; @@ -556,6 +557,8 @@ struct clk *__clk_create_clk(struct clk_core *clk_core) return ERR_PTR(-ENOMEM); clk->core = clk_core; + clk->dev_id = dev; + clk->con_id = con; return clk; } @@ -936,10 +939,25 @@ EXPORT_SYMBOL_GPL(clk_provider_disable); */ void clk_disable(struct clk *clk_user) { + struct clk_core *clk; + unsigned long flags; + if (IS_ERR_OR_NULL(clk_user)) return; - clk_provider_disable(clk_to_clk_core(clk_user)); + clk = clk_to_clk_core(clk_user); + + flags = clk_enable_lock(); + if (!WARN(clk_user->enable_count == 0, + "incorrect disable clk dev %s con %s last disabler %pF\n", + clk_user->dev_id, clk_user->con_id, clk_user->last_disable)) { + + clk_user->last_disable = __builtin_return_address(0); + clk_user->enable_count--; + + __clk_disable(clk); + } + clk_enable_unlock(flags); } EXPORT_SYMBOL_GPL(clk_disable); @@ -1000,10 +1018,22 @@ EXPORT_SYMBOL_GPL(clk_provider_enable); */ int clk_enable(struct clk *clk_user) { + struct clk_core *clk; + unsigned long flags; + int ret; + if (!clk_user) return 0; - return clk_provider_enable(clk_to_clk_core(clk_user)); + clk = clk_to_clk_core(clk_user); + + flags = clk_enable_lock(); + ret = __clk_enable(clk); + if (!ret) + clk_user->enable_count++; + clk_enable_unlock(flags); + + return ret; } EXPORT_SYMBOL_GPL(clk_enable); @@ -1698,7 +1728,7 @@ struct clk *clk_get_parent(struct clk *clk_user) clk = clk_to_clk_core(clk_user); parent = clk_provider_get_parent(clk); - return __clk_create_clk(parent); + return __clk_create_clk(parent, clk_user->dev_id, clk_user->con_id); } EXPORT_SYMBOL_GPL(clk_get_parent); diff --git a/drivers/clk/clk.h b/drivers/clk/clk.h index 3b3068b..49eff38 100644 --- a/drivers/clk/clk.h +++ b/drivers/clk/clk.h @@ -19,5 +19,6 @@ void of_clk_unlock(void); #endif #if defined(CONFIG_COMMON_CLK) -struct clk *__clk_create_clk(struct clk_core *clk_core); +struct clk *__clk_create_clk(struct clk_core *clk_core, const char *dev, + const char *con); #endif diff --git a/drivers/clk/clkdev.c b/drivers/clk/clkdev.c index 060041b..99ea87f 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -77,7 +77,9 @@ EXPORT_SYMBOL(of_clk_provider_get); struct clk *of_clk_get(struct device_node *np, int index) { - return __clk_create_clk(of_clk_provider_get(np, index)); + struct clk_core *clk = of_clk_provider_get(np, index); + + return __clk_create_clk(clk, np->full_name, NULL); } EXPORT_SYMBOL(of_clk_get); @@ -130,7 +132,9 @@ struct clk_core *of_clk_provider_get_by_name(struct device_node *np, const char */ struct clk *of_clk_get_by_name(struct device_node *np, const char *name) { - return __clk_create_clk(of_clk_provider_get_by_name(np, name)); + struct clk_core *clk = of_clk_provider_get_by_name(np, name); + + return __clk_create_clk(clk, np->full_name, NULL); } EXPORT_SYMBOL(of_clk_get_by_name); #endif @@ -202,7 +206,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) #if defined(CONFIG_COMMON_CLK) struct clk_core *clk = clk_provider_get_sys(dev_id, con_id); - return __clk_create_clk(clk); + return __clk_create_clk(clk, dev_id, con_id); #else struct clk_lookup *cl; @@ -242,7 +246,9 @@ EXPORT_SYMBOL(clk_provider_get); struct clk *clk_get(struct device *dev, const char *con_id) { #if defined(CONFIG_COMMON_CLK) - return __clk_create_clk(clk_provider_get(dev, con_id)); + const char *dev_id = dev ? dev_name(dev) : NULL; + + return __clk_create_clk(clk_provider_get(dev, con_id), dev_id, con_id); #else const char *dev_id = dev ? dev_name(dev) : NULL; struct clk *clk; diff --git a/include/linux/clk-private.h b/include/linux/clk-private.h index 2c1ece9..ce6a528 100644 --- a/include/linux/clk-private.h +++ b/include/linux/clk-private.h @@ -57,6 +57,11 @@ struct clk_core { struct clk { struct clk_core *core; + const char *dev_id; + const char *con_id; + + unsigned int enable_count; + void *last_disable; }; /*