diff options
author | tkasivajhula <tkasivajhula@nvidia.com> | 2010-02-25 17:47:21 -0800 |
---|---|---|
committer | Gary King <gking@nvidia.com> | 2010-03-02 15:10:39 -0800 |
commit | afa844561ffd7c29a0a7c2aac597ec4ae5ca7f51 (patch) | |
tree | 45eb6c0419ea2b4818100d5013eaefbfbc8c3a20 | |
parent | 39134556d653e86a6f58c1ecac24e660a7cd1627 (diff) |
tegra power: Use the scheduler to figure out when to go into LP2
Still being tested for performance.
Change-Id: I5be5619f90ada7bd277b1c042cd1cb4de4ff5124
Reviewed-on: http://git-master/r/710
Reviewed-by: Narendra Damahe <ndamahe@nvidia.com>
Tested-by: Narendra Damahe <ndamahe@nvidia.com>
Reviewed-by: Trivikram Kasivajhula <tkasivajhula@nvidia.com>
Reviewed-by: Gary King <gking@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/idle-t2.c | 139 |
1 files changed, 57 insertions, 82 deletions
diff --git a/arch/arm/mach-tegra/idle-t2.c b/arch/arm/mach-tegra/idle-t2.c index 80dda2ca4b0f..c45346178380 100644 --- a/arch/arm/mach-tegra/idle-t2.c +++ b/arch/arm/mach-tegra/idle-t2.c @@ -29,6 +29,7 @@ #include <linux/kernel.h> #include <linux/platform_device.h> #include <linux/wakelock.h> +#include "nvos.h" extern NvRmDeviceHandle s_hRmGlobal; extern void cpu_ap20_do_lp2(void); @@ -49,10 +50,8 @@ extern struct wake_lock main_wake_lock; #define CPU_CONTEXT_SAVE_AREA_SIZE 4096 #define TEMP_SAVE_AREA_SIZE 16 #define ENABLE_LP2 1 -#define NV_POWER_LP2_IDLE_THRESHOLD_MS 700 -#define NV_POWER_IDLE_WINDOW_SIZE 100 -#define MAX_LP2_TIME_US 1000000 -#define NV_POWER_COMPLETE_IDLE_MS 1000 +#define LP2_ROUNDTRIP_TIME 1 +#define LP2_PADDING_FACTOR 100 // When non-zero, collects and prints aggregate statistics about idle times static volatile NvU8 *s_pFlowCtrl = NULL; @@ -280,90 +279,66 @@ void cpu_ap20_do_idle(void) void mach_tegra_idle(void) { - static NvU32 flag = 0, lp2_time; - static NvU64 cur_jiffies = 0, old_jiffies = 0; - NvU64 delta_jif = 0; - NvU32 msec, delta; + static NvU32 flag = 0; + static NvU64 cur_jiffies = 0, next_timer; + static NvU32 msec = 0; + NvU64 delta_jif = 0; + static NvS32 lp2_time = 0; #ifdef CONFIG_WAKELOCK - //The wake lock api is ready if the main lock is ready - if (main_wake_lock.flags) - { - //Check if there are any IDLE locks pending - //If there are, then we do LP3. Else we do LP2 - if (!has_wake_lock(WAKE_LOCK_IDLE) && flag) - { - flag = 0; + //The wake lock api is ready if the main lock is ready + if (main_wake_lock.flags) + { + //Check if there are any IDLE locks pending + //If there are, then we do LP3. Else we do LP2 + if (!has_wake_lock(WAKE_LOCK_IDLE) && flag) + { + flag = 0; #if ENABLE_LP2 - //Only attempt LP2 if the flow controller is ready - if (s_pFlowCtrl) - { - if (num_online_cpus() > 1) - lp2safe = 1; - - if (num_online_cpus() == 1 && lp2safe) { - NvU32 dfs_low_corner = (NvRmPrivGetDfsFlags(s_hRmGlobal) & - NvRmDfsStatusFlags_Pause); - - if (dfs_low_corner) { - lp2count++; - NvSpareTimerTrigger(lp2_time); - cpu_ap20_do_lp2(); - NvRmPrivSetLp2TimeUS(s_hRmGlobal, MAX_LP2_TIME_US); - return; - } - } - } -#endif - } - } -#endif // CONFIG_WAKELOCK - lp3count++; - if (lp3count % NV_POWER_IDLE_WINDOW_SIZE == 0) - { - old_jiffies = cur_jiffies; - cur_jiffies = get_jiffies_64(); - delta_jif = cur_jiffies - old_jiffies; - msec = jiffies_to_msecs(delta_jif); - - //In a truly idle system, time spent in the idle loop - //will be very high due to the wfi. In a non-idle system - //we will enter and exit the idle loop quickly. As a result, - //we can say that the longer an IDLE_WINDOW, the more - //idle the system is. - if (msec > NV_POWER_LP2_IDLE_THRESHOLD_MS) - { - flag = 1; - - //The IDLE_WINDOW addresses the first axis - Performance. - //The second axis - Power savings, still needs to be addressed. - //The greater our LP2 duty cycle, the greater our power savings. - //We can say that the longer the IDLE_WINDOW, the more idle the - //system and, consequently, the longer we can stay in LP2. - if (msec > NV_POWER_COMPLETE_IDLE_MS) - msec = NV_POWER_COMPLETE_IDLE_MS; - - delta = NV_POWER_COMPLETE_IDLE_MS - msec; - - if (delta >= 300) - { - lp2_time = MAX_LP2_TIME_US / 8; - } - else if (delta >= 200) - { - lp2_time = MAX_LP2_TIME_US / 5; - } - else if (delta >= 100) + //Only attempt LP2 if the flow controller is ready + if (s_pFlowCtrl) { - lp2_time = MAX_LP2_TIME_US / 3; + if (num_online_cpus() > 1) + lp2safe = 1; + + if (num_online_cpus() == 1 && lp2safe) { + NvU32 dfs_low_corner = (NvRmPrivGetDfsFlags(s_hRmGlobal) & + NvRmDfsStatusFlags_Pause); + + if (dfs_low_corner) { + lp2count++; + NvSpareTimerTrigger(lp2_time); + cpu_ap20_do_lp2(); + + jiffies += msecs_to_jiffies(lp2_time / 1000); + NvRmPrivSetLp2TimeUS(s_hRmGlobal, lp2_time); + return; + } + } } - else - { - lp2_time = MAX_LP2_TIME_US; - } +#endif } - } - cpu_ap20_do_idle(); + } +#endif // CONFIG_WAKELOCK + lp3count++; + cur_jiffies = get_jiffies_64(); + next_timer = get_next_timer_interrupt(cur_jiffies); + delta_jif = next_timer - cur_jiffies; + msec = jiffies_to_msecs(delta_jif); + + lp2_time = msec - LP2_ROUNDTRIP_TIME * LP2_PADDING_FACTOR; + + if (lp2_time > 0) + { + if (num_online_cpus() > 1) + lp2safe = 1; + else + flag = 1; + + lp2_time *= 1000; + } + + cpu_ap20_do_idle(); } void mach_tegra_reset(void) |