From patchwork Wed Dec 14 03:53:58 2011 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Mike Turquette X-Patchwork-Id: 5656 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 5527223E01 for ; Wed, 14 Dec 2011 03:59:00 +0000 (UTC) Received: from mail-ey0-f180.google.com (mail-ey0-f180.google.com [209.85.215.180]) by fiordland.canonical.com (Postfix) with ESMTP id 4B77CA183C3 for ; Wed, 14 Dec 2011 03:59:00 +0000 (UTC) Received: by mail-ey0-f180.google.com with SMTP id k10so36706eaa.11 for ; Tue, 13 Dec 2011 19:59:00 -0800 (PST) Received: by 10.204.152.138 with SMTP id g10mr189828bkw.36.1323835138932; Tue, 13 Dec 2011 19:58:58 -0800 (PST) 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.205.129.2 with SMTP id hg2cs100509bkc; Tue, 13 Dec 2011 19:58:58 -0800 (PST) Received: by 10.68.191.70 with SMTP id gw6mr861380pbc.85.1323835136455; Tue, 13 Dec 2011 19:58:56 -0800 (PST) Received: from na3sys009aog120.obsmtp.com ([74.125.149.140]) by mx.google.com with SMTP id o4si5000236pbn.101.2011.12.13.19.58.52 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 13 Dec 2011 19:58:56 -0800 (PST) Received-SPF: pass (google.com: domain of mturquette@ti.com designates 74.125.149.140 as permitted sender) client-ip=74.125.149.140; Authentication-Results: mx.google.com; spf=pass (google.com: domain of mturquette@ti.com designates 74.125.149.140 as permitted sender) smtp.mail=mturquette@ti.com Received: from mail-yw0-f48.google.com ([209.85.213.48]) (using TLSv1) by na3sys009aob120.postini.com ([74.125.148.12]) with SMTP ID DSNKTuge+4a9rsdHjVYhd5O/OLEHT42g8A72@postini.com; Tue, 13 Dec 2011 19:58:56 PST Received: by mail-yw0-f48.google.com with SMTP id p56so1169657yhp.35 for ; Tue, 13 Dec 2011 19:58:51 -0800 (PST) Received: by 10.236.157.10 with SMTP id n10mr8656879yhk.41.1323835131717; Tue, 13 Dec 2011 19:58:51 -0800 (PST) Received: from localhost.localdomain (dragon.ti.com. [192.94.94.33]) by mx.google.com with ESMTPS id m38sm3562170anq.16.2011.12.13.19.58.48 (version=TLSv1/SSLv3 cipher=OTHER); Tue, 13 Dec 2011 19:58:51 -0800 (PST) Sender: "Turquette, Mike" From: Mike Turquette To: linux@arm.linux.org.uk Cc: linux-kernel@vger.kernel.org, linux-omap@vger.kernel.org, linux-arm-kernel@lists.infradead.org, jeremy.kerr@canonical.com, paul@pwsan.com, broonie@opensource.wolfsonmicro.com, tglx@linutronix.de, linus.walleij@stericsson.com, amit.kucheria@linaro.org, dsaxena@linaro.org, patches@linaro.org, linaro-dev@lists.linaro.org, grant.likely@secretlab.ca, sboyd@quicinc.com, shawn.guo@freescale.com, skannan@quicinc.com, magnus.damm@gmail.com, arnd.bergmann@linaro.org, eric.miao@linaro.org, richard.zhao@linaro.org, mturquette@linaro.org, mturquette@ti.com, andrew@lunn.ch, Yong Shen , Sascha Hauer Subject: [PATCH v4 6/6] clk: export the clk tree topology to debugfs Date: Tue, 13 Dec 2011 19:53:58 -0800 Message-Id: <1323834838-2206-7-git-send-email-mturquette@linaro.org> X-Mailer: git-send-email 1.7.5.4 In-Reply-To: <1323834838-2206-1-git-send-email-mturquette@linaro.org> References: <1323834838-2206-1-git-send-email-mturquette@linaro.org> Represents the clk tree as a directory hieraching in debugfs. Each clk is a directory filled with the following read-only entries: clk_rate clk_flags clk_prepare_count clk_enable_count clk_notifier_count This commit borrows some code from Yong Shen's patch to export clkdev clk's to debugfs: http://git.pengutronix.de/?p=imx/linux-2.6.git;a=commit;h=30aa15230747b3b92da16d841b1cf369f07192e7 Signed-off-by: Mike Turquette Cc: Yong Shen Cc: Sascha Hauer --- drivers/clk/Kconfig | 9 +++ drivers/clk/clk.c | 176 ++++++++++++++++++++++++++++++++++++++++++++++++++- include/linux/clk.h | 3 + 3 files changed, 186 insertions(+), 2 deletions(-) diff --git a/drivers/clk/Kconfig b/drivers/clk/Kconfig index ba7eb8c..09cc198 100644 --- a/drivers/clk/Kconfig +++ b/drivers/clk/Kconfig @@ -19,3 +19,12 @@ config GENERIC_CLK_BASIC help Allow use of basic, single-function clock types. These common definitions can be used across many platforms. + +config GENERIC_CLK_DEBUG + bool "Clock tree representation in debugs" + depends on GENERIC_CLK + help + Creates a directory hierchy in debugfs for visualizing the clk + tree structure as well. Each directory contains read-only + members that export information specific to that clk node: + clk_rate, clk_flags, clk_prepare_count & clk_enable_count. diff --git a/drivers/clk/clk.c b/drivers/clk/clk.c index f86cb98..a6ddbb1 100644 --- a/drivers/clk/clk.c +++ b/drivers/clk/clk.c @@ -23,6 +23,166 @@ static DEFINE_MUTEX(prepare_lock); static HLIST_HEAD(clk_root_list); static LIST_HEAD(clk_notifier_list); +/*** debugfs support ***/ + +#ifdef CONFIG_GENERIC_CLK_DEBUG +#include + +static struct dentry *rootdir; +static int inited = 0; + +/* caller must hold prepare_lock */ +static int clk_debug_create_one(struct clk *clk, struct dentry *pdentry) +{ + struct dentry *d; + int ret = -ENOMEM; + + if (!clk || !pdentry) { + ret = -EINVAL; + goto out; + } + + d = debugfs_create_dir(clk->name, pdentry); + if (!d) + goto out; + + clk->dentry = d; + + d = debugfs_create_u64("clk_rate", S_IRUGO, clk->dentry, + (u64 *)&clk->rate); + if (!d) + goto err_out; + + d = debugfs_create_x32("clk_flags", S_IRUGO, clk->dentry, + (u32 *)&clk->flags); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_prepare_count", S_IRUGO, clk->dentry, + (u32 *)&clk->prepare_count); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_enable_count", S_IRUGO, clk->dentry, + (u32 *)&clk->enable_count); + if (!d) + goto err_out; + + d = debugfs_create_u32("clk_notifier_count", S_IRUGO, clk->dentry, + (u32 *)&clk->notifier_count); + if (!d) + goto err_out; + + ret = 0; + goto out; + +err_out: + debugfs_remove(clk->dentry); +out: + return ret; +} + +/* caller must hold prepare_lock */ +static int clk_debug_create_subtree(struct clk *clk, struct dentry *pdentry) +{ + struct clk *child; + struct hlist_node *tmp; + int ret = -EINVAL;; + + if (!clk || !pdentry) + goto out; + + ret = clk_debug_create_one(clk, pdentry); + + if (ret) + goto out; + + hlist_for_each_entry(child, tmp, &clk->children, child_node) + clk_debug_create_subtree(child, clk->dentry); + + ret = 0; +out: + return ret; +} + +/** + * clk_debug_register - add a clk node to the debugfs clk tree + * @clk: the clk being added to the debugfs clk tree + * + * Dynamically adds a clk to the debugfs clk tree if debugfs has been + * initialized. Otherwise it bails out early since the debugfs clk tree + * will be created lazily by clk_debug_init as part of a late_initcall. + * + * Caller must hold prepare_lock. Only clk_init calls this function (so + * far) so this is taken care. + */ +static int clk_debug_register(struct clk *clk) +{ + struct clk *parent; + struct dentry *pdentry; + int ret = 0; + + if (!inited) + goto out; + + parent = clk->parent; + + /* + * Check to see if a clk is a root clk. Also check that it is + * safe to add this clk to debugfs + */ + if (!parent) + pdentry = rootdir; + else + if (parent->dentry) + pdentry = parent->dentry; + else + goto out; + + ret = clk_debug_create_subtree(clk, pdentry); + +out: + return ret; +} + +/** + * clk_debug_init - lazily create the debugfs clk tree visualization + * + * clks are often initialized very early during boot before memory can + * be dynamically allocated and well before debugfs is setup. + * clk_debug_init walks the clk tree hierarchy while holding + * prepare_lock and creates the topology as part of a late_initcall, + * thus insuring that clks initialized very early will still be + * represented in the debugfs clk tree. This function should only be + * called once at boot-time, and all other clks added dynamically will + * be done so with clk_debug_register. + */ +static int __init clk_debug_init(void) +{ + struct clk *root_clk; + struct hlist_node *tmp; + + rootdir = debugfs_create_dir("clk", NULL); + + if (!rootdir) + return -ENOMEM; + + mutex_lock(&prepare_lock); + + hlist_for_each_entry(root_clk, tmp, &clk_root_list, child_node) + clk_debug_create_subtree(root_clk, rootdir); + + inited = 1; + + mutex_unlock(&prepare_lock); + + return 0; +} +late_initcall(clk_debug_init); +#else +static inline int clk_debug_register(struct clk *clk) { return 0; } +#endif /* CONFIG_GENERIC_CLK_DEBUG */ + /*** clk API ***/ void __clk_unprepare(struct clk *clk) @@ -574,15 +734,25 @@ EXPORT_SYMBOL_GPL(clk_get_parent); void __clk_reparent(struct clk *clk, struct clk *new_parent) { + struct dentry *d; + if (!clk || !new_parent) return; hlist_del(&clk->child_node); hlist_add_head(&clk->child_node, &new_parent->children); - clk->parent = new_parent; +#ifdef CONFIG_GENERIC_CLK_DEBUG + d = debugfs_rename(clk->parent->dentry, clk->dentry, + new_parent->dentry, clk->name); + if (d) + clk->dentry = d; + else + pr_debug("%s: failed to reparent debugfs entry for %s\n", + __func__, clk->name); +#endif - /* FIXME update sysfs clock topology */ + clk->parent = new_parent; } /** @@ -697,6 +867,8 @@ void clk_init(struct device *dev, struct clk *clk) else clk->rate = 0; + clk_debug_register(clk); + mutex_unlock(&prepare_lock); return; diff --git a/include/linux/clk.h b/include/linux/clk.h index 55049ee..6cf3e2b 100644 --- a/include/linux/clk.h +++ b/include/linux/clk.h @@ -46,6 +46,9 @@ struct clk { struct hlist_head children; struct hlist_node child_node; unsigned int notifier_count; +#ifdef CONFIG_GENERIC_CLK_DEBUG + struct dentry *dentry; +#endif }; /**