aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorPeter 'p2' De Schrijver <peter.de-schrijver@nokia.com>2008-10-15 11:13:48 -0400
committerKevin Hilman <khilman@deeprootsystems.com>2009-09-02 18:08:24 -0400
commit331b93f41dff21c8f95709032cb184fb82bf2003 (patch)
tree6945e875909ae2571bd3344c978395414e61781c
parenta23456e9b02b3fae0fc78cb33fad69803a50e5bc (diff)
OMAP: PM: Add pm-debug counters
This patch provides the debugfs entries and a function which will be called by the PM code to register the time spent per domain per state. Also some new fields are added to the powerdomain struct to keep the time information. NOTE: As of v2.6.29, using getnstimeofday() after drivers are suspended is no longer safe since the timekeeping subsystem is also suspended as part of the suspend process. Instead use sched_clock() which on OMAP returns the 32k SYNC timer in nanoseconds. Also, do not print out status for meta powerdomains (dpll*) Signed-off-by: Peter 'p2' De Schrijver <peter.de-schrijver@nokia.com> Signed-off-by: Tero Kristo <tero.kristo@nokia.com> Signed-off-by: Kevin Hilman <khilman@deeprootsystems.com>
-rw-r--r--arch/arm/mach-omap2/pm-debug.c178
-rw-r--r--arch/arm/mach-omap2/pm.h4
-rw-r--r--arch/arm/plat-omap/include/mach/powerdomain.h5
3 files changed, 186 insertions, 1 deletions
diff --git a/arch/arm/mach-omap2/pm-debug.c b/arch/arm/mach-omap2/pm-debug.c
index da3a53f8ccc8..7383e85eac26 100644
--- a/arch/arm/mach-omap2/pm-debug.c
+++ b/arch/arm/mach-omap2/pm-debug.c
@@ -20,13 +20,15 @@
20 */ 20 */
21 21
22#include <linux/kernel.h> 22#include <linux/kernel.h>
23#include <linux/timer.h> 23#include <linux/sched.h>
24#include <linux/clk.h> 24#include <linux/clk.h>
25#include <linux/err.h> 25#include <linux/err.h>
26#include <linux/io.h> 26#include <linux/io.h>
27 27
28#include <mach/clock.h> 28#include <mach/clock.h>
29#include <mach/board.h> 29#include <mach/board.h>
30#include <mach/powerdomain.h>
31#include <mach/clockdomain.h>
30 32
31#include "prm.h" 33#include "prm.h"
32#include "cm.h" 34#include "cm.h"
@@ -150,3 +152,177 @@ void omap2_pm_dump(int mode, int resume, unsigned int us)
150 for (i = 0; i < reg_count; i++) 152 for (i = 0; i < reg_count; i++)
151 printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val); 153 printk(KERN_INFO "%-20s: 0x%08x\n", regs[i].name, regs[i].val);
152} 154}
155
156#ifdef CONFIG_DEBUG_FS
157#include <linux/debugfs.h>
158#include <linux/seq_file.h>
159
160struct dentry *pm_dbg_dir;
161
162static int pm_dbg_init_done;
163
164enum {
165 DEBUG_FILE_COUNTERS = 0,
166 DEBUG_FILE_TIMERS,
167};
168
169static const char pwrdm_state_names[][4] = {
170 "OFF",
171 "RET",
172 "INA",
173 "ON"
174};
175
176void pm_dbg_update_time(struct powerdomain *pwrdm, int prev)
177{
178 s64 t;
179
180 if (!pm_dbg_init_done)
181 return ;
182
183 /* Update timer for previous state */
184 t = sched_clock();
185
186 pwrdm->state_timer[prev] += t - pwrdm->timer;
187
188 pwrdm->timer = t;
189}
190
191static int clkdm_dbg_show_counter(struct clockdomain *clkdm, void *user)
192{
193 struct seq_file *s = (struct seq_file *)user;
194
195 if (strcmp(clkdm->name, "emu_clkdm") == 0 ||
196 strcmp(clkdm->name, "wkup_clkdm") == 0 ||
197 strncmp(clkdm->name, "dpll", 4) == 0)
198 return 0;
199
200 seq_printf(s, "%s->%s (%d)", clkdm->name,
201 clkdm->pwrdm.ptr->name,
202 atomic_read(&clkdm->usecount));
203 seq_printf(s, "\n");
204
205 return 0;
206}
207
208static int pwrdm_dbg_show_counter(struct powerdomain *pwrdm, void *user)
209{
210 struct seq_file *s = (struct seq_file *)user;
211 int i;
212
213 if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
214 strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
215 strncmp(pwrdm->name, "dpll", 4) == 0)
216 return 0;
217
218 if (pwrdm->state != pwrdm_read_pwrst(pwrdm))
219 printk(KERN_ERR "pwrdm state mismatch(%s) %d != %d\n",
220 pwrdm->name, pwrdm->state, pwrdm_read_pwrst(pwrdm));
221
222 seq_printf(s, "%s (%s)", pwrdm->name,
223 pwrdm_state_names[pwrdm->state]);
224 for (i = 0; i < 4; i++)
225 seq_printf(s, ",%s:%d", pwrdm_state_names[i],
226 pwrdm->state_counter[i]);
227
228 seq_printf(s, "\n");
229
230 return 0;
231}
232
233static int pwrdm_dbg_show_timer(struct powerdomain *pwrdm, void *user)
234{
235 struct seq_file *s = (struct seq_file *)user;
236 int i;
237
238 if (strcmp(pwrdm->name, "emu_pwrdm") == 0 ||
239 strcmp(pwrdm->name, "wkup_pwrdm") == 0 ||
240 strncmp(pwrdm->name, "dpll", 4) == 0)
241 return 0;
242
243 pwrdm_state_switch(pwrdm);
244
245 seq_printf(s, "%s (%s)", pwrdm->name,
246 pwrdm_state_names[pwrdm->state]);
247
248 for (i = 0; i < 4; i++)
249 seq_printf(s, ",%s:%lld", pwrdm_state_names[i],
250 pwrdm->state_timer[i]);
251
252 seq_printf(s, "\n");
253 return 0;
254}
255
256static int pm_dbg_show_counters(struct seq_file *s, void *unused)
257{
258 pwrdm_for_each(pwrdm_dbg_show_counter, s);
259 clkdm_for_each(clkdm_dbg_show_counter, s);
260
261 return 0;
262}
263
264static int pm_dbg_show_timers(struct seq_file *s, void *unused)
265{
266 pwrdm_for_each(pwrdm_dbg_show_timer, s);
267 return 0;
268}
269
270static int pm_dbg_open(struct inode *inode, struct file *file)
271{
272 switch ((int)inode->i_private) {
273 case DEBUG_FILE_COUNTERS:
274 return single_open(file, pm_dbg_show_counters,
275 &inode->i_private);
276 case DEBUG_FILE_TIMERS:
277 default:
278 return single_open(file, pm_dbg_show_timers,
279 &inode->i_private);
280 };
281}
282
283static const struct file_operations debug_fops = {
284 .open = pm_dbg_open,
285 .read = seq_read,
286 .llseek = seq_lseek,
287 .release = single_release,
288};
289
290static int __init pwrdms_setup(struct powerdomain *pwrdm, void *unused)
291{
292 int i;
293 s64 t;
294
295 t = sched_clock();
296
297 for (i = 0; i < 4; i++)
298 pwrdm->state_timer[i] = 0;
299
300 pwrdm->timer = t;
301
302 return 0;
303}
304
305static int __init pm_dbg_init(void)
306{
307 struct dentry *d;
308
309 d = debugfs_create_dir("pm_debug", NULL);
310 if (IS_ERR(d))
311 return PTR_ERR(d);
312
313 (void) debugfs_create_file("count", S_IRUGO,
314 d, (void *)DEBUG_FILE_COUNTERS, &debug_fops);
315 (void) debugfs_create_file("time", S_IRUGO,
316 d, (void *)DEBUG_FILE_TIMERS, &debug_fops);
317
318 pwrdm_for_each(pwrdms_setup, NULL);
319
320 pm_dbg_init_done = 1;
321
322 return 0;
323}
324late_initcall(pm_dbg_init);
325
326#else
327void pm_dbg_update_time(struct powerdomain *pwrdm, int prev) {}
328#endif
diff --git a/arch/arm/mach-omap2/pm.h b/arch/arm/mach-omap2/pm.h
index 21201cd4117b..4589db1c8af8 100644
--- a/arch/arm/mach-omap2/pm.h
+++ b/arch/arm/mach-omap2/pm.h
@@ -11,12 +11,16 @@
11#ifndef __ARCH_ARM_MACH_OMAP2_PM_H 11#ifndef __ARCH_ARM_MACH_OMAP2_PM_H
12#define __ARCH_ARM_MACH_OMAP2_PM_H 12#define __ARCH_ARM_MACH_OMAP2_PM_H
13 13
14#include <mach/powerdomain.h>
15
14#ifdef CONFIG_PM_DEBUG 16#ifdef CONFIG_PM_DEBUG
15extern void omap2_pm_dump(int mode, int resume, unsigned int us); 17extern void omap2_pm_dump(int mode, int resume, unsigned int us);
16extern int omap2_pm_debug; 18extern int omap2_pm_debug;
19extern void pm_dbg_update_time(struct powerdomain *pwrdm, int prev);
17#else 20#else
18#define omap2_pm_dump(mode, resume, us) do {} while (0); 21#define omap2_pm_dump(mode, resume, us) do {} while (0);
19#define omap2_pm_debug 0 22#define omap2_pm_debug 0
23#define pm_dbg_update_time(pwrdm, prev) do {} while (0);
20#endif /* CONFIG_PM_DEBUG */ 24#endif /* CONFIG_PM_DEBUG */
21 25
22extern void omap24xx_idle_loop_suspend(void); 26extern void omap24xx_idle_loop_suspend(void);
diff --git a/arch/arm/plat-omap/include/mach/powerdomain.h b/arch/arm/plat-omap/include/mach/powerdomain.h
index de03f3dbbf3d..6271d8556a40 100644
--- a/arch/arm/plat-omap/include/mach/powerdomain.h
+++ b/arch/arm/plat-omap/include/mach/powerdomain.h
@@ -119,6 +119,11 @@ struct powerdomain {
119 119
120 int state; 120 int state;
121 unsigned state_counter[4]; 121 unsigned state_counter[4];
122
123#ifdef CONFIG_PM_DEBUG
124 s64 timer;
125 s64 state_timer[4];
126#endif
122}; 127};
123 128
124 129