summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJonas Aaberg <jonas.aberg@stericsson.com>2011-05-27 11:59:04 +0200
committerUlf Hansson <ulf.hansson@stericsson.com>2011-09-19 15:15:32 +0200
commit3d6e0bf9c42825608d03acf63436cba774baf0c5 (patch)
tree3051a5306c93b7d2cd09251c0802057d767107ae
parente74b083fb24b94959e8080b47a1f26512bdf58db (diff)
ARM: ux500: cpuidle_dbg: Show reason why ApIdle
Add debug code to show the reason why we're in ApIdle and not in ApSleep. ST-Ericsson Linux next: ER338824 ST-Ericsson ID: - ST-Ericsson FOSS-OUT ID: Trivial Change-Id: I652a5708f08c279b4a2a322bab45ea8eac693e56 Signed-off-by: Jonas Aaberg <jonas.aberg@stericsson.com> Reviewed-on: http://gerrit.lud.stericsson.com/gerrit/24043 Reviewed-by: QATEST Reviewed-by: Rickard ANDERSSON <rickard.andersson@stericsson.com>
-rw-r--r--arch/arm/mach-ux500/pm/cpuidle.c4
-rw-r--r--arch/arm/mach-ux500/pm/cpuidle_dbg.c46
-rw-r--r--arch/arm/mach-ux500/pm/cpuidle_dbg.h10
3 files changed, 57 insertions, 3 deletions
diff --git a/arch/arm/mach-ux500/pm/cpuidle.c b/arch/arm/mach-ux500/pm/cpuidle.c
index fe04634a5b2..bba32577259 100644
--- a/arch/arm/mach-ux500/pm/cpuidle.c
+++ b/arch/arm/mach-ux500/pm/cpuidle.c
@@ -352,6 +352,10 @@ static int determine_sleep_state(u32 *sleep_time)
break;
}
+ ux500_ci_dbg_register_reason(i, power_state_req,
+ (*sleep_time),
+ max_depth);
+
return max(CI_WFI, i);
}
diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.c b/arch/arm/mach-ux500/pm/cpuidle_dbg.c
index 5d3315dbf70..d74743c53c1 100644
--- a/arch/arm/mach-ux500/pm/cpuidle_dbg.c
+++ b/arch/arm/mach-ux500/pm/cpuidle_dbg.c
@@ -62,6 +62,10 @@ struct state_history {
u32 exit_counter;
u32 timed_out;
ktime_t measure_begin;
+ int ape_blocked;
+ int time_blocked;
+ int both_blocked;
+ int gov_blocked;
struct state_history_state *states;
};
static DEFINE_PER_CPU(struct state_history, *state_history);
@@ -78,6 +82,11 @@ static int deepest_allowed_state = CONFIG_U8500_CPUIDLE_DEEPEST_STATE;
static u32 measure_latency;
static bool wake_latency;
+static bool apidle_both_blocked;
+static bool apidle_ape_blocked;
+static bool apidle_time_blocked;
+static bool apidle_gov_blocked;
+
static struct cstate *cstates;
static int cstates_len;
static DEFINE_SPINLOCK(dbg_lock);
@@ -324,11 +333,23 @@ static void state_record_time(struct state_history *sh, int ctarget,
sh->states[sh->state].counter++;
}
+void ux500_ci_dbg_register_reason(int idx, bool power_state_req,
+ u32 time, u32 max_depth)
+{
+
+
+ if (cstates[idx].state == CI_IDLE) {
+ apidle_ape_blocked = power_state_req;
+ apidle_time_blocked = time < cstates[idx + 1].threshold;
+ apidle_both_blocked = power_state_req && apidle_time_blocked;
+ apidle_gov_blocked = cstates[max_depth].state == CI_IDLE;
+ }
+}
+
void ux500_ci_dbg_log(int ctarget, ktime_t enter_time)
{
int i;
ktime_t now;
-
unsigned long flags;
struct state_history *sh;
struct state_history *sh_other;
@@ -342,6 +363,17 @@ void ux500_ci_dbg_log(int ctarget, ktime_t enter_time)
spin_lock_irqsave(&dbg_lock, flags);
+ if (cstates[ctarget].state == CI_IDLE) {
+ if (apidle_both_blocked)
+ sh->both_blocked++;
+ if (apidle_ape_blocked)
+ sh->ape_blocked++;
+ if (apidle_time_blocked)
+ sh->time_blocked++;
+ if (apidle_gov_blocked)
+ sh->gov_blocked++;
+ }
+
/*
* Check if current state is just a repeat of
* the state we're already in, then just quit.
@@ -419,9 +451,14 @@ static void state_history_reset(void)
sh->start = ktime_get();
sh->measure_begin = sh->start;
- sh->state = cstates_len; /* CI_RUNNING */
+ /* Don't touch sh->state, since that is where we are now */
+
sh->exit_counter = 0;
sh->timed_out = 0;
+ sh->ape_blocked = 0;
+ sh->time_blocked = 0;
+ sh->both_blocked = 0;
+ sh->gov_blocked = 0;
}
spin_unlock_irqrestore(&dbg_lock, flags);
}
@@ -533,6 +570,11 @@ static void stats_disp_one(struct seq_file *s, struct state_history *sh,
seq_printf(s, " in %d ms %d%%",
(u32) t_us, (u32)perc);
+ if (cstates[i].state == CI_IDLE)
+ seq_printf(s, ", reg:%d time:%d both:%d gov:%d",
+ sh->ape_blocked, sh->time_blocked,
+ sh->both_blocked, sh->gov_blocked);
+
if (sh->states[i].counter)
seq_printf(s, ", hit rate: %u%% ",
100 * sh->states[i].hit_rate /
diff --git a/arch/arm/mach-ux500/pm/cpuidle_dbg.h b/arch/arm/mach-ux500/pm/cpuidle_dbg.h
index 143b8cf48d8..406106038ad 100644
--- a/arch/arm/mach-ux500/pm/cpuidle_dbg.h
+++ b/arch/arm/mach-ux500/pm/cpuidle_dbg.h
@@ -9,6 +9,8 @@
#ifndef CPUIDLE_DBG_H
#define CPUIDLE_DBG_H
+#include "cpuidle.h"
+
#ifdef CONFIG_U8500_CPUIDLE_DEBUG
void ux500_ci_dbg_init(void);
void ux500_ci_dbg_remove(void);
@@ -17,7 +19,9 @@ void ux500_ci_dbg_log(int ctarget, ktime_t enter_time);
void ux500_ci_dbg_wake_latency(int ctarget, int sleep_time);
void ux500_ci_dbg_exit_latency(int ctarget, ktime_t now, ktime_t exit,
ktime_t enter, bool timed_out);
-void ux500_ci_dbg_wake_timer(bool timed);
+
+void ux500_ci_dbg_register_reason(int idx, bool power_state_req,
+ u32 sleep_time, u32 max_depth);
bool ux500_ci_dbg_force_ape_on(void);
int ux500_ci_dbg_deepest_state(void);
@@ -40,6 +44,10 @@ static inline void ux500_ci_dbg_exit_latency(int ctarget,
ktime_t enter, bool timed_out) { }
static inline void ux500_ci_dbg_wake_latency(int ctarget, int sleep_time) { }
+
+static inline void ux500_ci_dbg_register_reason(int idx, bool power_state_req,
+ u32 sleep_time, u32 max_depth) { }
+
static inline bool ux500_ci_dbg_force_ape_on(void)
{
return false;