From patchwork Fri Jul 13 14:19:43 2012 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tero Kristo X-Patchwork-Id: 1196061 Return-Path: X-Original-To: patchwork-linux-arm@patchwork.kernel.org Delivered-To: patchwork-process-083081@patchwork2.kernel.org Received: from merlin.infradead.org (merlin.infradead.org [205.233.59.134]) by patchwork2.kernel.org (Postfix) with ESMTP id 50E54DFFFD for ; Fri, 13 Jul 2012 14:36:57 +0000 (UTC) Received: from localhost ([::1] helo=merlin.infradead.org) by merlin.infradead.org with esmtp (Exim 4.76 #1 (Red Hat Linux)) id 1SpgsT-0001x7-Du; Fri, 13 Jul 2012 14:29:53 +0000 Received: from bear.ext.ti.com ([192.94.94.41]) by merlin.infradead.org with esmtps (Exim 4.76 #1 (Red Hat Linux)) id 1SpgjA-0008S0-A0 for linux-arm-kernel@lists.infradead.org; Fri, 13 Jul 2012 14:20:56 +0000 Received: from dlelxv30.itg.ti.com ([172.17.2.17]) by bear.ext.ti.com (8.13.7/8.13.7) with ESMTP id q6DEJxV1017820; Fri, 13 Jul 2012 09:19:59 -0500 Received: from DLEE74.ent.ti.com (dlee74.ent.ti.com [157.170.170.8]) by dlelxv30.itg.ti.com (8.13.8/8.13.8) with ESMTP id q6DEJxLL023618; Fri, 13 Jul 2012 09:19:59 -0500 Received: from dlelxv22.itg.ti.com (172.17.1.197) by DLEE74.ent.ti.com (157.170.170.8) with Microsoft SMTP Server id 14.1.323.3; Fri, 13 Jul 2012 09:19:59 -0500 Received: from localhost.localdomain (h64-15.vpn.ti.com [172.24.64.15]) by dlelxv22.itg.ti.com (8.13.8/8.13.8) with ESMTP id q6DEJn59007873; Fri, 13 Jul 2012 09:19:58 -0500 From: Tero Kristo To: , , Subject: [PATCHv4 6/8] ARM: OMAP: pm-debug: enhanced usecount debug support Date: Fri, 13 Jul 2012 17:19:43 +0300 Message-ID: <1342189185-5306-7-git-send-email-t-kristo@ti.com> X-Mailer: git-send-email 1.7.4.1 In-Reply-To: <1342189185-5306-1-git-send-email-t-kristo@ti.com> References: <1342189185-5306-1-git-send-email-t-kristo@ti.com> MIME-Version: 1.0 X-Spam-Note: CRM114 invocation failed X-Spam-Score: -4.2 (----) X-Spam-Report: SpamAssassin version 3.3.2 on merlin.infradead.org summary: Content analysis details: (-4.2 points) pts rule name description ---- ---------------------- -------------------------------------------------- -2.3 RCVD_IN_DNSWL_MED RBL: Sender listed at http://www.dnswl.org/, medium trust [192.94.94.41 listed in list.dnswl.org] -0.0 T_RP_MATCHES_RCVD Envelope sender domain matches handover relay domain -0.0 SPF_PASS SPF: sender matches SPF record -1.9 BAYES_00 BODY: Bayes spam probability is 0 to 1% [score: 0.0000] Cc: linux-arm-kernel@lists.infradead.org X-BeenThere: linux-arm-kernel@lists.infradead.org X-Mailman-Version: 2.1.14 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Sender: linux-arm-kernel-bounces@lists.infradead.org Errors-To: linux-arm-kernel-bounces+patchwork-linux-arm=patchwork.kernel.org@lists.infradead.org Voltdm, pwrdm, clkdm, hwmod and clk usecounts are now separeted to their own file, 'usecount'. This file shows the usecounts for every active domain and their children recursively. 'count' file now only shows power state counts for powerdomains. This patch also provices a way to do printk dumps from kernel code, by calling the pm_dbg_dump_X functions. The plan is to call these functions once an error condition is detected, e.g. failed suspend. Signed-off-by: Tero Kristo Cc: Paul Walmsley Cc: Kevin Hilman --- arch/arm/mach-omap2/pm-debug.c | 128 ++++++++++++++++++++++++++++++++++------ arch/arm/mach-omap2/pm.h | 6 ++ 2 files changed, 115 insertions(+), 19 deletions(-) diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c index 814bcd9..cfc46a8 100644 --- a/arch/arm/mach-omap2/pm-debug.c +++ b/arch/arm/mach-omap2/pm-debug.c @@ -51,6 +51,7 @@ static int pm_dbg_init(void); enum { DEBUG_FILE_COUNTERS = 0, DEBUG_FILE_TIMERS, + DEBUG_FILE_USECOUNT, }; static const char pwrdm_state_names[][PWRDM_MAX_PWRSTS] = { @@ -75,23 +76,6 @@ void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) pwrdm->timer = t; } -static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user) -{ - struct seq_file *s = (struct seq_file *)user; - - if (strcmp(clkdm->name, "emu_clkdm") == 0 || - strcmp(clkdm->name, "wkup_clkdm") == 0 || - strncmp(clkdm->name, "dpll", 4) == 0) - return 0; - - seq_printf(s, "%s->%s (%d)", clkdm->name, - clkdm->pwrdm.ptr->name, - atomic_read(&clkdm->usecount)); - seq_printf(s, "\n"); - - return 0; -} - static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user) { struct seq_file *s = (struct seq_file *)user; @@ -145,11 +129,112 @@ static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user) return 0; } +static struct voltagedomain *parent_voltdm; +static struct powerdomain *parent_pwrdm; +static struct clockdomain *parent_clkdm; + +#define PM_DBG_PRINT(s, fmt, args...) \ + { \ + if (s) \ + seq_printf(s, fmt, ## args); \ + else \ + pr_info(fmt, ## args); \ + } + +static int _pm_dbg_dump_clk(struct clk *clk, void *user) +{ + struct seq_file *s = user; + + if (clk->clkdm == parent_clkdm && clk->usecount && !clk->autoidle) + PM_DBG_PRINT(s, " ck:%s: %d\n", clk->name, clk->usecount); + + return 0; +} + +static int _pm_dbg_dump_hwmod(struct omap_hwmod *oh, void *user) +{ + struct seq_file *s = user; + + if (oh->clkdm != parent_clkdm) + return 0; + + if (oh->_state != _HWMOD_STATE_ENABLED) + return 0; + + PM_DBG_PRINT(s, " oh:%s: enabled\n", oh->name); + + return 0; +} + +static int _pm_dbg_dump_clkdm(struct clockdomain *clkdm, void *user) +{ + struct seq_file *s = user; + u32 usecount; + + if (clkdm->pwrdm.ptr == parent_pwrdm) { + usecount = atomic_read(&clkdm->usecount); + if (usecount) { + PM_DBG_PRINT(s, " cd:%s: %d\n", clkdm->name, + usecount); + parent_clkdm = clkdm; + omap_hwmod_for_each(_pm_dbg_dump_hwmod, s); + omap_clk_for_each(_pm_dbg_dump_clk, s); + } + } + return 0; +} + +static int _pm_dbg_dump_pwrdm(struct powerdomain *pwrdm, void *user) +{ + struct seq_file *s = user; + u32 usecount; + + if (pwrdm->voltdm.ptr == parent_voltdm) { + usecount = atomic_read(&pwrdm->usecount); + if (usecount) { + PM_DBG_PRINT(s, " pd:%s: %d\n", pwrdm->name, usecount); + parent_pwrdm = pwrdm; + clkdm_for_each(_pm_dbg_dump_clkdm, s); + } + } + return 0; +} + +void pm_dbg_dump_pwrdm(struct powerdomain *pwrdm) +{ + pr_info("pd:%s: %d\n", pwrdm->name, atomic_read(&pwrdm->usecount)); + parent_pwrdm = pwrdm; + clkdm_for_each(_pm_dbg_dump_clkdm, NULL); +} + +void pm_dbg_dump_voltdm(struct voltagedomain *voltdm) +{ + pr_info("vd:%s: %d\n", voltdm->name, atomic_read(&voltdm->usecount)); + parent_voltdm = voltdm; + pwrdm_for_each(_pm_dbg_dump_pwrdm, NULL); +} + +static int _voltdm_dbg_show_counters(struct voltagedomain *voltdm, void *user) +{ + struct seq_file *s = user; + + seq_printf(s, "vd:%s: %d\n", voltdm->name, + atomic_read(&voltdm->usecount)); + + parent_voltdm = voltdm; + pwrdm_for_each(_pm_dbg_dump_pwrdm, s); + return 0; +} + +static int pm_dbg_show_usecount(struct seq_file *s, void *unused) +{ + voltdm_for_each(_voltdm_dbg_show_counters, s); + return 0; +} + static int pm_dbg_show_counters(struct seq_file *s, void *unused) { pwrdm_for_each(pwrdm_dbg_show_counter, s); - clkdm_for_each(clkdm_dbg_show_counter, s); - return 0; } @@ -162,6 +247,9 @@ static int pm_dbg_show_timers(struct seq_file *s, void *unused) static int pm_dbg_open(struct inode *inode, struct file *file) { switch ((int)inode->i_private) { + case DEBUG_FILE_USECOUNT: + return single_open(file, pm_dbg_show_usecount, + &inode->i_private); case DEBUG_FILE_COUNTERS: return single_open(file, pm_dbg_show_counters, &inode->i_private); @@ -271,6 +359,8 @@ static int __init pm_dbg_init(void) d, (void *)DEBUG_FILE_COUNTERS, &debug_fops); (void) debugfs_create_file("time", S_IRUGO, d, (void *)DEBUG_FILE_TIMERS, &debug_fops); + (void) debugfs_create_file("usecount", S_IRUGO, + d, (void *)DEBUG_FILE_USECOUNT, &debug_fops); pwrdm_for_each(pwrdms_setup, (void *)d); diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h index 7856489..312f2de 100644 --- a/arch/arm/mach-omap2/pm.h +++ b/arch/arm/mach-omap2/pm.h @@ -41,10 +41,16 @@ static inline int omap4_opp_init(void) extern int omap3_pm_get_suspend_state(struct powerdomain *pwrdm); extern int omap3_pm_set_suspend_state(struct powerdomain *pwrdm, int state); +struct clk; + #ifdef CONFIG_PM_DEBUG extern u32 enable_off_mode; +extern void pm_dbg_dump_pwrdm(struct powerdomain *pwrdm); +extern void pm_dbg_dump_voltdm(struct voltagedomain *voltdm); #else #define enable_off_mode 0 +static inline void pm_dbg_dump_pwrdm(struct powerdomain *pwrdm) { } +static inline void pm_dbg_dump_voltdm(struct voltagedomain *voltdm) { } #endif #if defined(CONFIG_PM_DEBUG) && defined(CONFIG_DEBUG_FS)