summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/pm.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2013-08-14 20:47:30 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2013-09-14 13:41:44 -0700
commit4e13d190b1264c897b38bfd74cfbe67ace9b7f16 (patch)
treed3237e36ee850c5c5f8de4a9d588a5e3461b4def /arch/arm/mach-tegra/pm.c
parentb7b860af6bb06ca9250b7cfb9091de0c45084953 (diff)
ARM: tegra: power: Add cluster switch time stats
Expanded cluster switch instrumentation with simple timing statistic: running window average, exponential average, maximum switch time - aggregated separately for LP/G and G/LP cluster switch. Added the respective debugfs node. Moved cluster switch start/end timing samples to exactly match interrupt-disabled section of the switch. Replaced cluster instrumentation error message with debug print. The INSTRUMENT_CLUSTER_SWITCH compile option is still disabled, so by default all changes in this commit are not compiled in. Change-Id: If7b9c7b1469f6839e20b7c8db3aa9cf2c0592f2d Signed-off-by: Alex Frid <afrid@nvidia.com> Reviewed-on: http://git-master/r/262859 Reviewed-by: Bo Yan <byan@nvidia.com>
Diffstat (limited to 'arch/arm/mach-tegra/pm.c')
-rw-r--r--arch/arm/mach-tegra/pm.c129
1 files changed, 103 insertions, 26 deletions
diff --git a/arch/arm/mach-tegra/pm.c b/arch/arm/mach-tegra/pm.c
index 647c549b35bc..4a4df6789233 100644
--- a/arch/arm/mach-tegra/pm.c
+++ b/arch/arm/mach-tegra/pm.c
@@ -222,31 +222,54 @@ static struct tegra_suspend_platform_data *pdata;
static enum tegra_suspend_mode current_suspend_mode = TEGRA_SUSPEND_NONE;
#if defined(CONFIG_TEGRA_CLUSTER_CONTROL) && INSTRUMENT_CLUSTER_SWITCH
-enum tegra_cluster_switch_time_id {
- tegra_cluster_switch_time_id_start = 0,
- tegra_cluster_switch_time_id_prolog,
- tegra_cluster_switch_time_id_switch,
- tegra_cluster_switch_time_id_epilog,
- tegra_cluster_switch_time_id_max
-};
-
static unsigned long
tegra_cluster_switch_times[tegra_cluster_switch_time_id_max];
-#define tegra_cluster_switch_time(flags, id) \
- do { \
- barrier(); \
- if (flags & TEGRA_POWER_CLUSTER_MASK) { \
- void __iomem *timer_us = \
- IO_ADDRESS(TEGRA_TMRUS_BASE); \
- if (id < tegra_cluster_switch_time_id_max) \
- tegra_cluster_switch_times[id] = \
- readl(timer_us); \
- wmb(); \
- } \
- barrier(); \
- } while(0)
-#else
-#define tegra_cluster_switch_time(flags, id) do {} while(0)
+struct tegra_cluster_switch_time_stats {
+ unsigned long sum;
+ unsigned long avg;
+ unsigned long exp_avg;
+ unsigned long max;
+ int cnt;
+};
+
+static struct tegra_cluster_switch_time_stats lp2g_stats;
+static struct tegra_cluster_switch_time_stats g2lp_stats;
+
+void tegra_cluster_switch_time(unsigned int flags, int id)
+{
+ unsigned long t;
+ struct tegra_cluster_switch_time_stats *stats;
+
+ if (!(flags & TEGRA_POWER_CLUSTER_MASK) ||
+ (id >= tegra_cluster_switch_time_id_max))
+ return;
+
+ tegra_cluster_switch_times[id] = tegra_read_usec_raw();
+ wmb();
+ if (id != tegra_cluster_switch_time_id_end)
+ return;
+
+ stats = flags & TEGRA_POWER_CLUSTER_G ? &lp2g_stats : &g2lp_stats;
+
+ t = tegra_cluster_switch_times[tegra_cluster_switch_time_id_end] -
+ tegra_cluster_switch_times[tegra_cluster_switch_time_id_start];
+ if (stats->max < t)
+ stats->max = t;
+
+ stats->sum += t;
+ stats->cnt++;
+ if (stats->cnt < CLUSTER_SWITCH_AVG_SAMPLES)
+ return;
+
+ stats->avg = stats->sum;
+ stats->cnt = stats->sum = 0;
+ if (!stats->exp_avg) {
+ stats->exp_avg = stats->avg; /* 1st window sample */
+ return;
+ }
+ stats->exp_avg = (stats->exp_avg * (CLUSTER_SWITCH_AVG_SAMPLES - 1) +
+ stats->avg) >> CLUSTER_SWITCH_TIME_AVG_SHIFT;
+}
#endif
#ifdef CONFIG_PM_SLEEP
@@ -697,8 +720,6 @@ unsigned int tegra_idle_power_down_last(unsigned int sleep_time,
reg &= ~TEGRA_POWER_EFFECT_LP0;
writel(reg, pmc + PMC_CTRL);
- tegra_cluster_switch_time(flags, tegra_cluster_switch_time_id_start);
-
/*
* We can use clk_get_rate_all_locked() here, because all other cpus
* are in LP2 state and irqs are disabled
@@ -846,7 +867,7 @@ unsigned int tegra_idle_power_down_last(unsigned int sleep_time,
#if INSTRUMENT_CLUSTER_SWITCH
if (flags & TEGRA_POWER_CLUSTER_MASK) {
- pr_err("%s: prolog %lu us, switch %lu us, epilog %lu us, total %lu us\n",
+ pr_debug("%s: prolog %lu us, switch %lu us, epilog %lu us, total %lu us\n",
is_lp_cluster() ? "G=>LP" : "LP=>G",
tegra_cluster_switch_times[tegra_cluster_switch_time_id_prolog] -
tegra_cluster_switch_times[tegra_cluster_switch_time_id_start],
@@ -1945,3 +1966,59 @@ void tegra_tsc_wait_for_resume(void)
}
}
#endif
+
+#if defined(CONFIG_DEBUG_FS) && INSTRUMENT_CLUSTER_SWITCH
+
+static void cluster_switch_stats_show(
+ struct seq_file *s, struct tegra_cluster_switch_time_stats *stats)
+{
+ seq_printf(s, "%u-samples average: %lu\n",
+ CLUSTER_SWITCH_AVG_SAMPLES,
+ stats->avg >> CLUSTER_SWITCH_TIME_AVG_SHIFT);
+ seq_printf(s, "exponential average: %lu\n",
+ stats->exp_avg >> CLUSTER_SWITCH_TIME_AVG_SHIFT);
+ seq_printf(s, "maximum since boot: %lu\n\n", stats->max);
+}
+
+
+static int tegra_cluster_switch_stats_show(struct seq_file *s, void *data)
+{
+ seq_printf(s, "G=>LP cluster switch timing: (us)\n");
+ cluster_switch_stats_show(s, &g2lp_stats);
+ seq_printf(s, "LP=>G cluster switch timing: (us)\n");
+ cluster_switch_stats_show(s, &lp2g_stats);
+ return 0;
+}
+
+static int tegra_cluster_switch_stats_open(
+ struct inode *inode, struct file *file)
+{
+ return single_open(file, tegra_cluster_switch_stats_show,
+ inode->i_private);
+}
+
+static const struct file_operations tegra_cluster_switch_stats_ops = {
+ .open = tegra_cluster_switch_stats_open,
+ .read = seq_read,
+ .llseek = seq_lseek,
+ .release = single_release,
+};
+
+static int __init tegra_pm_core_debug_init(void)
+{
+ struct dentry *dir, *d;
+
+ dir = debugfs_create_dir("tegra_pm_core", NULL);
+ if (!dir)
+ return -ENOMEM;
+
+ d = debugfs_create_file("cluster_switch_stats", S_IRUGO, dir, NULL,
+ &tegra_cluster_switch_stats_ops);
+ if (!d)
+ return -ENOMEM;
+
+ return 0;
+}
+
+late_initcall(tegra_pm_core_debug_init);
+#endif