From: vishwanath.sripa...@linaro.org

This patch has instrumentation code for measuring CPUIdle C states for OMAP.
THis is still under development and not completely tested yet.
Idea here is to capture the timestamp at various phases of CPU Idle and 
then compute the sw latency for various c states. For OMAP, 32k clock is
chosen as reference clock this as is an always on clock. 
wkup domain memory (scratchpad memory) is used for storing timestamps.

Signed-off-by: Vishwanath BS <vishwanath.sripa...@linaro.org>
---
diff --git a/arch/arm/mach-omap2/cpuidle34xx.c 
b/arch/arm/mach-omap2/cpuidle34xx.c
index 3d3d035..30120cb
--- a/arch/arm/mach-omap2/cpuidle34xx.c
+++ b/arch/arm/mach-omap2/cpuidle34xx.c
@@ -25,6 +25,8 @@
 #include <linux/sched.h>
 #include <linux/cpuidle.h>
 
+#include <linux/clk.h>
+#include <linux/jiffies.h>
 #include <plat/prcm.h>
 #include <plat/irqs.h>
 #include <plat/powerdomain.h>
@@ -33,6 +35,7 @@
 #include <plat/serial.h>
 
 #include "pm.h"
+#include <plat/common.h>
 
 #ifdef CONFIG_CPU_IDLE
 
@@ -86,6 +89,13 @@ static struct cpuidle_params cpuidle_params_table[] = {
        {1, 10000, 30000, 300000},
 };
 
+#ifdef CONFIG_CPU_IDLE_PROF
+static struct clk *clk_32k;
+#define CONVERT_32K_USEC(lat) (lat * (USEC_PER_SEC/clk_get_rate(clk_32k)))
+u32 omap3_sram_get_wkup_time();
+u32 omap3_sram_get_sleep_time();
+#endif
+
 static int omap3_idle_bm_check(void)
 {
        if (!omap3_can_sleep())
@@ -115,21 +125,26 @@ static int _cpuidle_deny_idle(struct powerdomain *pwrdm,
  * Called from the CPUidle framework to program the device to the
  * specified target state selected by the governor.
  */
+
+
 static int omap3_enter_idle(struct cpuidle_device *dev,
                        struct cpuidle_state *state)
 {
        struct omap3_processor_cx *cx = cpuidle_get_statedata(state);
        struct timespec ts_preidle, ts_postidle, ts_idle;
        u32 mpu_state = cx->mpu_state, core_state = cx->core_state;
+       int idle_time, latency;
+       long sleep_time, wkup_time, total_sleep_time, preidle_time, 
postidle_time;
 
        current_cx_state = *cx;
 
-       /* Used to keep track of the total time in idle */
-       getnstimeofday(&ts_preidle);
-
        local_irq_disable();
        local_fiq_disable();
-
+       /* Used to keep track of the total time in idle */
+       getnstimeofday(&ts_preidle);
+#ifdef CONFIG_CPU_IDLE_PROF
+       preidle_time = omap_32k_read();
+#endif
        pwrdm_set_next_pwrst(mpu_pd, mpu_state);
        pwrdm_set_next_pwrst(core_pd, core_state);
 
@@ -153,9 +168,27 @@ return_sleep_time:
        getnstimeofday(&ts_postidle);
        ts_idle = timespec_sub(ts_postidle, ts_preidle);
 
+#ifdef CONFIG_CPU_IDLE_PROF
+       postidle_time = omap_32k_read();
+#endif
        local_irq_enable();
        local_fiq_enable();
 
+#ifdef CONFIG_CPU_IDLE_PROF
+       /* TODO: take care of overflow */
+       idle_time = postidle_time - preidle_time;
+       sleep_time = omap3_sram_get_sleep_time();
+       wkup_time = omap3_sram_get_wkup_time();
+
+       /* TODO: take care of overflow */
+       total_sleep_time = wkup_time -  sleep_time;
+       latency = idle_time - total_sleep_time;
+       /* TODO: calculate average */
+       state->actual_latency = CONVERT_32K_USEC(latency);
+       state->sleep_latency = CONVERT_32K_USEC(sleep_time - preidle_time);
+       state->wkup_latency = CONVERT_32K_USEC(postidle_time - wkup_time);
+#endif
+
        return ts_idle.tv_nsec / NSEC_PER_USEC + ts_idle.tv_sec * USEC_PER_SEC;
 }
 
@@ -419,6 +452,7 @@ struct cpuidle_driver omap3_idle_driver = {
  */
 int __init omap3_idle_init(void)
 {
+       static struct device dummy_device;
        int i, count = 0;
        struct omap3_processor_cx *cx;
        struct cpuidle_state *state;
@@ -456,6 +490,9 @@ int __init omap3_idle_init(void)
 
        omap3_cpuidle_update_states();
 
+#ifdef CONFIG_CPU_IDLE_PROF
+       clk_32k = clk_get(&dummy_device, "wkup_32k_fck");
+#endif
        if (cpuidle_register_device(dev)) {
                printk(KERN_ERR "%s: CPUidle register device failed\n",
                       __func__);
diff --git a/arch/arm/mach-omap2/sleep34xx.S b/arch/arm/mach-omap2/sleep34xx.S
index d522cd7..448f1ba
--- a/arch/arm/mach-omap2/sleep34xx.S
+++ b/arch/arm/mach-omap2/sleep34xx.S
@@ -58,6 +58,9 @@
 #define SDRC_MANUAL_1_P                (OMAP343X_SDRC_BASE + SDRC_MANUAL_1)
 #define SDRC_DLLA_STATUS_V     OMAP34XX_SDRC_REGADDR(SDRC_DLLA_STATUS)
 #define SDRC_DLLA_CTRL_V       OMAP34XX_SDRC_REGADDR(SDRC_DLLA_CTRL)
+#define TIMER_32K_SYNC         0xfa320010
+#define SCRATCHPAD_SLEEP_TIME          0xfa0029f8
+#define SCRATCHPAD_WKUP_TIME           0xfa0029fc
 
         .text
 /* Function to aquire the semaphore in scratchpad */
@@ -184,6 +187,22 @@ api_params:
 ENTRY(save_secure_ram_context_sz)
        .word   . - save_secure_ram_context
 
+ENTRY(omap3_sram_get_wkup_time)
+    stmfd   sp!, {lr}     @ save registers on stack
+       ldr r0, wkup_time
+       ldr r0, [r0]
+    ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(omap3_sram_get_wkup_time_sz)
+        .word   . - omap3_sram_get_wkup_time
+
+ENTRY(omap3_sram_get_sleep_time)
+    stmfd   sp!, {lr}     @ save registers on stack
+       ldr r0, sleep_time
+       ldr r0, [r0]
+    ldmfd   sp!, {pc}     @ restore regs and return
+ENTRY(omap3_sram_get_sleep_time_sz)
+        .word   . - omap3_sram_get_sleep_time
+
 /*
  * Forces OMAP into idle state
  *
@@ -207,6 +226,13 @@ loop:
        cmp     r1, #0x0
        /* If context save is required, do that and execute wfi */
        bne     save_context_wfi
+
+#ifdef CONFIG_CPU_IDLE_PROF
+       ldr r4, sync_32k_timer
+       ldr     r5, [r4]
+       ldr r6, sleep_time
+       str r5, [r6]
+#endif
        /* Data memory barrier and Data sync barrier */
        mov     r1, #0
        mcr     p15, 0, r1, c7, c10, 4
@@ -224,8 +250,15 @@ loop:
        nop
        nop
        nop
+#ifdef CONFIG_CPU_IDLE_PROF
+       ldr r4, sync_32k_timer
+       ldr     r5, [r4]
+       ldr r6, wkup_time
+       str r5, [r6]
+#endif
        bl wait_sdrc_ok
 
+
        ldmfd   sp!, {r0-r12, pc}               @ restore regs and return
 restore_es3:
        /*b restore_es3*/               @ Enable to debug restore code
@@ -587,6 +620,12 @@ finished:
        mcr     p15, 2, r10, c0, c0, 0
        isb
 skip_l2_inval:
+#ifdef CONFIG_CPU_IDLE_PROF
+       ldr r4, sync_32k_timer
+       ldr     r5, [r4]
+       ldr r6, sleep_time
+       str r5, [r6]
+#endif
        /* Data memory barrier and Data sync barrier */
        mov     r1, #0
        mcr     p15, 0, r1, c7, c10, 4
@@ -603,6 +642,13 @@ skip_l2_inval:
        nop
        nop
        nop
+
+#ifdef CONFIG_CPU_IDLE_PROF
+       ldr r4, sync_32k_timer
+       ldr     r5, [r4]
+       ldr r6, wkup_time
+       str r5, [r6]
+#endif
        bl wait_sdrc_ok
        /* restore regs and return */
        ldmfd   sp!, {r0-r12, pc}
@@ -668,5 +714,14 @@ cache_pred_disable_mask:
        .word   0xFFFFE7FB
 control_stat:
        .word   CONTROL_STAT
+sync_32k_timer:
+       .word TIMER_32K_SYNC
+sleep_time:
+       .word SCRATCHPAD_SLEEP_TIME
+wkup_time:
+       .word SCRATCHPAD_WKUP_TIME
+
 ENTRY(omap34xx_cpu_suspend_sz)
        .word   . - omap34xx_cpu_suspend
+
+
diff --git a/drivers/cpuidle/Kconfig b/drivers/cpuidle/Kconfig
index 7dbc4a8..b8f1e07 100644
--- a/drivers/cpuidle/Kconfig
+++ b/drivers/cpuidle/Kconfig
@@ -18,3 +18,8 @@ config CPU_IDLE_GOV_MENU
        bool
        depends on CPU_IDLE && NO_HZ
        default y
+
+config CPU_IDLE_PROF
+       bool
+       depends on CPU_IDLE
+       default y
diff --git a/drivers/cpuidle/sysfs.c b/drivers/cpuidle/sysfs.c
index 0310ffa..a3e9db1
--- a/drivers/cpuidle/sysfs.c
+++ b/drivers/cpuidle/sysfs.c
@@ -249,6 +249,11 @@ define_show_state_ull_function(usage)
 define_show_state_ull_function(time)
 define_show_state_str_function(name)
 define_show_state_str_function(desc)
+#ifdef CONFIG_CPU_IDLE_PROF
+define_show_state_function(actual_latency)
+define_show_state_function(sleep_latency)
+define_show_state_function(wkup_latency)
+#endif
 
 define_one_state_ro(name, show_state_name);
 define_one_state_ro(desc, show_state_desc);
@@ -256,7 +261,11 @@ define_one_state_ro(latency, show_state_exit_latency);
 define_one_state_ro(power, show_state_power_usage);
 define_one_state_ro(usage, show_state_usage);
 define_one_state_ro(time, show_state_time);
-
+#ifdef CONFIG_CPU_IDLE_PROF
+define_one_state_ro(actual_latency, show_state_actual_latency);
+define_one_state_ro(sleep_latency, show_state_sleep_latency);
+define_one_state_ro(wkup_latency, show_state_wkup_latency);
+#endif
 static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_name.attr,
        &attr_desc.attr,
@@ -264,6 +273,11 @@ static struct attribute *cpuidle_state_default_attrs[] = {
        &attr_power.attr,
        &attr_usage.attr,
        &attr_time.attr,
+#ifdef CONFIG_CPU_IDLE_PROF
+       &attr_actual_latency.attr,
+       &attr_sleep_latency.attr,
+       &attr_wkup_latency.attr,
+#endif
        NULL
 };
 
diff --git a/include/linux/cpuidle.h b/include/linux/cpuidle.h
index 55215cc..6474f6a 100644
--- a/include/linux/cpuidle.h
+++ b/include/linux/cpuidle.h
@@ -43,6 +43,9 @@ struct cpuidle_state {
 
        int (*enter)    (struct cpuidle_device *dev,
                         struct cpuidle_state *state);
+#ifdef CONFIG_CPU_IDLE_PROF
+       u32 actual_latency, sleep_latency, wkup_latency;
+#endif
 };
 
 /* Idle State Flags */

_______________________________________________
linaro-dev mailing list
linaro-dev@lists.linaro.org
http://lists.linaro.org/mailman/listinfo/linaro-dev

Reply via email to