From patchwork Tue Sep 23 18:44:12 2014 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tomeu Vizoso X-Patchwork-Id: 4958961 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 F30A39F3DF for ; Tue, 23 Sep 2014 18:47:59 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id A04712025A for ; Tue, 23 Sep 2014 18:47:58 +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 4577F20259 for ; Tue, 23 Sep 2014 18:47:57 +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 1XWV5W-0004w6-Q4; Tue, 23 Sep 2014 18:45:22 +0000 Received: from mail-wg0-x231.google.com ([2a00:1450:400c:c00::231]) by bombadil.infradead.org with esmtps (Exim 4.80.1 #2 (Red Hat Linux)) id 1XWV5G-0003Vb-3L for linux-arm-kernel@lists.infradead.org; Tue, 23 Sep 2014 18:45:07 +0000 Received: by mail-wg0-f49.google.com with SMTP id x12so5003101wgg.20 for ; Tue, 23 Sep 2014 11:44:43 -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=DHNLM0pfGVO2F3kCKvFtWdwtcnWslvUem5aJS2X9Z68=; b=rTBaqat9pSwmJiLMEdj0ThZiZUGzmjXu5v3LmJgDKkFAf1jfKj8aaJ8jov83woaRkH BX8xhQmHuLyfql4gwfEeninPeSYRBq5RyYC06tXt/oZzhJsj5Ef+Xqw8o1ddpQARqFa7 Qv8huZsT/H/Vkc8V9RIbxmVKmO9VPFgaGtaw8LB57x8ofhCrOf33UhkZx+2R7Td4F4Nm UaHCfWP+TcIeOD47FRgSqR95qeCqRhnmHRQu1D3xSBEt5m5K1QdgxmQmRGVAbf6old0n qOD3zDcEA8/XDvVNbbeD7Efb8vD/a9hXGrXU6Jcs49WLWtUx7FyjLy6mTJrrEaCDKmng 9OzA== X-Received: by 10.180.99.34 with SMTP id en2mr25688097wib.34.1411497883861; Tue, 23 Sep 2014 11:44:43 -0700 (PDT) Received: from cizrna.lan (37-48-33-192.tmcz.cz. [37.48.33.192]) by mx.google.com with ESMTPSA id pn5sm16871650wjc.4.2014.09.23.11.44.38 for (version=TLSv1.2 cipher=ECDHE-RSA-AES128-GCM-SHA256 bits=128/128); Tue, 23 Sep 2014 11:44:42 -0700 (PDT) From: Tomeu Vizoso To: Mike Turquette Subject: [PATCH v13 4/9] clk: per-user clock accounting for debug Date: Tue, 23 Sep 2014 20:44:12 +0200 Message-Id: <1411497857-24726-2-git-send-email-tomeu.vizoso@collabora.com> X-Mailer: git-send-email 1.9.3 In-Reply-To: <1411497857-24726-1-git-send-email-tomeu.vizoso@collabora.com> References: <1411497613-24049-1-git-send-email-tomeu.vizoso@collabora.com> <1411497857-24726-1-git-send-email-tomeu.vizoso@collabora.com> X-CRM114-Version: 20100106-BlameMichelson ( TRE 0.8.0 (BSD) ) MR-646709E3 X-CRM114-CacheID: sfid-20140923_114506_458652_291DDC5C X-CRM114-Status: GOOD ( 16.79 ) X-Spam-Score: -0.7 (/) Cc: Russell King , 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.5 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 | 11 ++++++----- include/linux/clk-private.h | 5 +++++ 4 files changed, 47 insertions(+), 10 deletions(-) diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index ffe58ec..b34922e 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; } @@ -980,10 +983,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); @@ -1044,10 +1062,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); @@ -1745,7 +1775,7 @@ struct clk *clk_get_parent(struct clk *clk_user) if (IS_ERR(parent)) return (void *)parent; - parent_user = __clk_create_clk(parent); + parent_user = __clk_create_clk(parent, clk_user->dev_id, clk_user->con_id); if (IS_ERR(parent_user)) __clk_put(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 f99c1e4..8699a9b 100644 --- a/drivers/clk/clkdev.c +++ b/drivers/clk/clkdev.c @@ -36,7 +36,7 @@ static DEFINE_MUTEX(clocks_mutex); typedef struct clk_core clkdev_ret_t; #else typedef struct clk clkdev_ret_t; -#define __clk_create_clk(clk) clk +#define __clk_create_clk(clk, dev_id, con_id) clk #define clk_to_clk_core(clk) clk #endif @@ -96,7 +96,7 @@ struct clk *of_clk_get(struct device_node *np, int index) if (IS_ERR(clk)) return (void *)clk; - clk_user = __clk_create_clk(clk); + clk_user = __clk_create_clk(clk, np->full_name, NULL); if (IS_ERR(clk_user)) __clk_put(clk); @@ -160,7 +160,7 @@ struct clk *of_clk_get_by_name(struct device_node *np, const char *name) if (IS_ERR(clk)) return (void *)clk; - clk_user = __clk_create_clk(clk); + clk_user = __clk_create_clk(clk, np->full_name, NULL); if (IS_ERR(clk_user)) __clk_put(clk); @@ -238,7 +238,7 @@ struct clk *clk_get_sys(const char *dev_id, const char *con_id) if (IS_ERR(clk)) return (void *)clk; - clk_user = __clk_create_clk(clk); + clk_user = __clk_create_clk(clk, dev_id, con_id); if (IS_ERR(clk_user)) __clk_put(clk); @@ -265,6 +265,7 @@ EXPORT_SYMBOL(clk_provider_get); struct clk *clk_get(struct device *dev, const char *con_id) { + const char *dev_id = dev ? dev_name(dev) : NULL; clkdev_ret_t *clk; struct clk *clk_user; @@ -272,7 +273,7 @@ struct clk *clk_get(struct device *dev, const char *con_id) if (IS_ERR(clk)) return (void *)clk; - clk_user = __clk_create_clk(clk); + clk_user = __clk_create_clk(clk, dev_id, con_id); if (IS_ERR(clk_user)) __clk_put(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; }; /*