diff options
author | Alex Frid <afrid@nvidia.com> | 2011-09-10 18:33:28 -0700 |
---|---|---|
committer | Varun Colbert <vcolbert@nvidia.com> | 2011-09-13 15:58:31 -0700 |
commit | d52a93527778b13efd2e4b783ce0707513f53f26 (patch) | |
tree | 3b2b3a9c9e7b7f793e18a88875e02e1eea4be525 | |
parent | 6eb2a692ce69d0cff090b670118f91b56c123f17 (diff) |
ARM: tegra: power: Enforce cpufreq policy maximum
Tegra cpu complex frequency is set by cpufreq driver to the maximum
of per-cpu target frequencies specified by the respective governors
running on each cpu core. It guarantees that final frequency is above
all per-cpu policy low limits, but policy high limit set on one core,
may be exceeded if the other core has higher target.
This commit implements complementary mode in cpufreq driver that set
final cpu frequency below all per-cpu maximum policy limits. The new
mode is disabled by default, and can be activated via
/sys/module/cpu_tegra/parameters/force_policy_max
Change-Id: I079b7c55b079cdf62afae469b59f4b2cf0fc97d0
Reviewed-on: http://git-master/r/51722
Tested-by: Aleksandr Frid <afrid@nvidia.com>
Reviewed-by: Scott Williams <scwilliams@nvidia.com>
Reviewed-by: Satya Popuri <spopuri@nvidia.com>
Reviewed-by: Yu-Huan Hsu <yhsu@nvidia.com>
Reviewed-by: Diwakar Tundlam <dtundlam@nvidia.com>
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.c | 62 |
1 files changed, 61 insertions, 1 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index dc6d36738379..f7ffbce75154 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -51,11 +51,39 @@ static struct cpufreq_frequency_table *freq_table; static struct clk *cpu_clk; static struct clk *emc_clk; +static unsigned long policy_max_speed[CONFIG_NR_CPUS]; static unsigned long target_cpu_speed[CONFIG_NR_CPUS]; static DEFINE_MUTEX(tegra_cpu_lock); static bool is_suspended; static int suspend_index; +static bool force_policy_max; + +static int force_policy_max_set(const char *arg, const struct kernel_param *kp) +{ + int ret; + bool old_policy = force_policy_max; + + ret = param_set_bool(arg, kp); + + if ((ret == 0) && (old_policy != force_policy_max)) + tegra_cpu_set_speed_cap(NULL); + + return ret; +} + +static int force_policy_max_get(char *buffer, const struct kernel_param *kp) +{ + return param_get_bool(buffer, kp); +} + +static struct kernel_param_ops policy_ops = { + .set = force_policy_max_set, + .get = force_policy_max_get, +}; +module_param_cb(force_policy_max, &policy_ops, &force_policy_max, 0644); + + #ifdef CONFIG_TEGRA_THERMAL_THROTTLE static ssize_t show_throttle(struct cpufreq_policy *policy, char *buf) @@ -389,11 +417,16 @@ unsigned long tegra_cpu_lowest_speed(void) { } unsigned long tegra_cpu_highest_speed(void) { + unsigned long policy_max = ULONG_MAX; unsigned long rate = 0; int i; - for_each_online_cpu(i) + for_each_online_cpu(i) { + if (force_policy_max) + policy_max = min(policy_max, policy_max_speed[i]); rate = max(rate, target_cpu_speed[i]); + } + rate = min(rate, policy_max); return rate; } @@ -512,6 +545,25 @@ static int tegra_cpu_exit(struct cpufreq_policy *policy) return 0; } +static int tegra_cpufreq_policy_notifier( + struct notifier_block *nb, unsigned long event, void *data) +{ + int i, ret; + struct cpufreq_policy *policy = data; + + if (event == CPUFREQ_NOTIFY) { + ret = cpufreq_frequency_table_target(policy, freq_table, + policy->max, CPUFREQ_RELATION_H, &i); + policy_max_speed[policy->cpu] = + ret ? policy->max : freq_table[i].frequency; + } + return NOTIFY_OK; +} + +static struct notifier_block tegra_cpufreq_policy_nb = { + .notifier_call = tegra_cpufreq_policy_notifier, +}; + static struct freq_attr *tegra_cpufreq_attr[] = { &cpufreq_freq_attr_scaling_available_freqs, #ifdef CONFIG_TEGRA_THERMAL_THROTTLE @@ -551,6 +603,12 @@ static int __init tegra_cpufreq_init(void) freq_table = table_data->freq_table; tegra_cpu_edp_init(false); + + ret = cpufreq_register_notifier( + &tegra_cpufreq_policy_nb, CPUFREQ_POLICY_NOTIFIER); + if (ret) + return ret; + return cpufreq_register_driver(&tegra_cpufreq_driver); } @@ -560,6 +618,8 @@ static void __exit tegra_cpufreq_exit(void) tegra_cpu_edp_exit(); tegra_auto_hotplug_exit(); cpufreq_unregister_driver(&tegra_cpufreq_driver); + cpufreq_unregister_notifier( + &tegra_cpufreq_policy_nb, CPUFREQ_POLICY_NOTIFIER); } |