diff options
author | Alex Frid <afrid@nvidia.com> | 2011-04-19 23:38:46 -0700 |
---|---|---|
committer | Dan Willemsen <dwillemsen@nvidia.com> | 2011-11-30 21:42:32 -0800 |
commit | ab3a31fc1c2fdea90c0be47f40b603675103bc96 (patch) | |
tree | 5e5b052a67866a460dd303f14e5b27ede7649b29 /arch | |
parent | df2009abf96414d23278f5342296d645b43a9fde (diff) |
ARM: tegra: power: Update Tegra3 CPU auto-hotplug
- taking CPU core off-line: selected CPU with minimum load
- switching from ULP to G CPU mode: set CPU clock to cpufreq
target rate after the mode switch is completed
Original-Change-Id: I9bf4d0f4b48c262cf678c603aac02043dd602674
Reviewed-on: http://git-master/r/28420
Reviewed-by: Varun Colbert <vcolbert@nvidia.com>
Tested-by: Varun Colbert <vcolbert@nvidia.com>
Original-Change-Id: I5a19be79dd8f8fe788637870a22cd34dcfea150e
Rebase-Id: Re264ec676c5c2103f7738c9eab5f4e11a4344975
Diffstat (limited to 'arch')
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.c | 45 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 4 | ||||
-rw-r--r-- | arch/arm/mach-tegra/pm.h | 5 |
3 files changed, 45 insertions, 9 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index dae7042c350f..baf543674c3d 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -55,7 +55,6 @@ static bool is_suspended; unsigned int tegra_getspeed(unsigned int cpu); static int tegra_update_cpu_speed(unsigned long rate); -static unsigned long tegra_cpu_highest_speed(void); #ifdef CONFIG_TEGRA_THERMAL_THROTTLE /* CPU frequency is gradually lowered when throttling is enabled */ @@ -117,7 +116,7 @@ void tegra_throttling_enable(bool enable) cancel_delayed_work_sync(&throttle_work); is_throttling = false; /* restore speed requested by governor */ - tegra_update_cpu_speed(tegra_cpu_highest_speed()); + tegra_cpu_cap_highest_speed(NULL); } mutex_unlock(&tegra_cpu_lock); @@ -241,7 +240,7 @@ static int tegra_cpu_edp_notify( cpu_speed = tegra_getspeed(0); new_speed = edp_governor_speed(cpu_speed); - if (cpu_speed != new_speed) { + if (new_speed < cpu_speed) { ret = tegra_update_cpu_speed(new_speed); if (ret) { cpu_clear(cpu, edp_cpumask); @@ -363,8 +362,29 @@ static int tegra_update_cpu_speed(unsigned long rate) return 0; } -static unsigned long tegra_cpu_highest_speed(void) -{ +unsigned int tegra_get_slowest_cpu_n(void) { + unsigned int cpu = nr_cpu_ids; + unsigned long rate = ULONG_MAX; + int i; + + for_each_online_cpu(i) + if ((i > 0) && (rate > target_cpu_speed[i])) { + cpu = i; + rate = target_cpu_speed[i]; + } + return cpu; +} + +unsigned long tegra_cpu_lowest_speed(void) { + unsigned long rate = ULONG_MAX; + int i; + + for_each_online_cpu(i) + rate = min(rate, target_cpu_speed[i]); + return rate; +} + +unsigned long tegra_cpu_highest_speed(void) { unsigned long rate = 0; int i; @@ -373,6 +393,17 @@ static unsigned long tegra_cpu_highest_speed(void) return rate; } +int tegra_cpu_cap_highest_speed(unsigned int *speed_cap) +{ + unsigned int new_speed = tegra_cpu_highest_speed(); + + new_speed = throttle_governor_speed(new_speed); + new_speed = edp_governor_speed(new_speed); + if (speed_cap) + *speed_cap = new_speed; + return tegra_update_cpu_speed(new_speed); +} + static int tegra_target(struct cpufreq_policy *policy, unsigned int target_freq, unsigned int relation) @@ -395,9 +426,7 @@ static int tegra_target(struct cpufreq_policy *policy, freq = freq_table[idx].frequency; target_cpu_speed[policy->cpu] = freq; - new_speed = throttle_governor_speed(tegra_cpu_highest_speed()); - new_speed = edp_governor_speed(new_speed); - ret = tegra_update_cpu_speed(new_speed); + ret = tegra_cpu_cap_highest_speed(&new_speed); if (ret == 0) tegra_auto_hotplug_governor(new_speed); out: diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index 16b3d0b2fd65..88adea4fd792 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -190,7 +190,7 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) case TEGRA_HP_IDLE: break; case TEGRA_HP_DOWN: - cpu = cpumask_next(0, cpu_online_mask); + cpu = tegra_get_slowest_cpu_n(); if (cpu < nr_cpu_ids) { up = false; queue_delayed_work( @@ -210,6 +210,8 @@ static void tegra_auto_hotplug_work_func(struct work_struct *work) if(!clk_set_parent(cpu_clk, cpu_g_clk)) { hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); + /* catch-up with governor target speed */ + tegra_cpu_cap_highest_speed(NULL); } queue_delayed_work( hotplug_wq, &hotplug_work, up2gn_delay); diff --git a/arch/arm/mach-tegra/pm.h b/arch/arm/mach-tegra/pm.h index 756fd4da3b61..0f1719ed5a36 100644 --- a/arch/arm/mach-tegra/pm.h +++ b/arch/arm/mach-tegra/pm.h @@ -81,6 +81,11 @@ void __init tegra_init_suspend(struct tegra_suspend_platform_data *plat); void tegra_idle_lp2(void); +unsigned int tegra_get_slowest_cpu_n(void); +unsigned long tegra_cpu_lowest_speed(void); +unsigned long tegra_cpu_highest_speed(void); +int tegra_cpu_cap_highest_speed(unsigned int *speed_cap); + struct tegra_edp_limits { int temperature; unsigned int freq_limits[CONFIG_NR_CPUS]; |