diff options
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.c | 40 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra.h | 3 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpu-tegra3.c | 11 | ||||
-rw-r--r-- | arch/arm/mach-tegra/cpuquiet.c | 7 | ||||
-rw-r--r-- | arch/arm/mach-tegra/tegra3_throttle.c | 5 |
5 files changed, 40 insertions, 26 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c index d864e9b96ba4..854f34777b8f 100644 --- a/arch/arm/mach-tegra/cpu-tegra.c +++ b/arch/arm/mach-tegra/cpu-tegra.c @@ -7,7 +7,7 @@ * Colin Cross <ccross@google.com> * Based on arch/arm/plat-omap/cpu-omap.c, (C) 2005 Nokia Corporation * - * Copyright (C) 2010-2012 NVIDIA CORPORATION. All rights reserved. + * Copyright (C) 2010-2013 NVIDIA CORPORATION. All rights reserved. * * This software is licensed under the terms of the GNU General Public * License version 2, as published by the Free Software Foundation, and @@ -66,7 +66,7 @@ static int force_policy_max_set(const char *arg, const struct kernel_param *kp) ret = param_set_bool(arg, kp); if ((ret == 0) && (old_policy != force_policy_max)) - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); mutex_unlock(&tegra_cpu_lock); return ret; @@ -99,7 +99,7 @@ static inline void _cpu_user_cap_set_locked(void) cpu_user_cap = freq_table[i].frequency; } #endif - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); } void tegra_cpu_user_cap_set(unsigned int speed_khz) @@ -212,10 +212,11 @@ static unsigned int edp_predict_limit(unsigned int cpus) return limit; } +/* Must be called while holding cpu_tegra_lock */ static void edp_update_limit(void) { unsigned int limit = edp_predict_limit(cpumask_weight(&edp_cpumask)); - + BUG_ON(!mutex_is_locked(&tegra_cpu_lock)); #ifdef CONFIG_TEGRA_EDP_EXACT_FREQ edp_limit = limit; #else @@ -263,7 +264,7 @@ int tegra_edp_set_cur_state(struct thermal_cooling_device *cdev, tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, true, 0); if (target_cpu_speed[0]) { edp_update_limit(); - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); } tegra_cpu_dvfs_alter(edp_thermal_index, &edp_cpumask, false, 0); mutex_unlock(&tegra_cpu_lock); @@ -299,7 +300,7 @@ int tegra_system_edp_alarm(bool alarm) or alarm is canceled */ if (target_cpu_speed[0]) { edp_update_limit(); - ret = tegra_cpu_set_speed_cap(NULL); + ret = tegra_cpu_set_speed_cap_locked(NULL); } if (!ret || !alarm) tegra_edp_throttle_cpu_now(0); @@ -359,7 +360,7 @@ static int tegra_cpu_edp_notify( cpu_speed = tegra_getspeed(0); new_speed = edp_governor_speed(cpu_speed); if (new_speed < cpu_speed) { - ret = tegra_cpu_set_speed_cap(NULL); + ret = tegra_cpu_set_speed_cap_locked(NULL); printk(KERN_DEBUG "cpu-tegra:%sforce EDP limit %u kHz" "\n", ret ? " failed to " : " ", new_speed); } @@ -378,7 +379,7 @@ static int tegra_cpu_edp_notify( tegra_cpu_dvfs_alter( edp_thermal_index, &edp_cpumask, true, event); edp_update_limit(); - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); mutex_unlock(&tegra_cpu_lock); break; } @@ -615,7 +616,7 @@ void tegra_cpu_set_volt_cap(unsigned int cap) mutex_lock(&tegra_cpu_lock); if (cap != volt_capped_speed) { volt_capped_speed = cap; - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); } mutex_unlock(&tegra_cpu_lock); if (cap) @@ -631,11 +632,12 @@ static unsigned int volt_cap_speed(unsigned int requested_speed) return requested_speed; } -int tegra_cpu_set_speed_cap(unsigned int *speed_cap) +/* Must be called with tegra_cpu_lock held */ +int tegra_cpu_set_speed_cap_locked(unsigned int *speed_cap) { int ret = 0; unsigned int new_speed = tegra_cpu_highest_speed(); - + BUG_ON(!mutex_is_locked(&tegra_cpu_lock)); #ifdef CONFIG_TEGRA_EDP_LIMITS edp_update_limit(); #endif @@ -656,6 +658,16 @@ int tegra_cpu_set_speed_cap(unsigned int *speed_cap) return ret; } +int tegra_cpu_set_speed_cap(unsigned int *speed_cap) +{ + int ret; + mutex_lock(&tegra_cpu_lock); + ret = tegra_cpu_set_speed_cap_locked(speed_cap); + mutex_unlock(&tegra_cpu_lock); + return ret; +} + + int tegra_suspended_target(unsigned int target_freq) { unsigned int new_speed = target_freq; @@ -689,7 +701,7 @@ static int tegra_target(struct cpufreq_policy *policy, freq = freq_table[idx].frequency; target_cpu_speed[policy->cpu] = freq; - ret = tegra_cpu_set_speed_cap(&new_speed); + ret = tegra_cpu_set_speed_cap_locked(&new_speed); _out: mutex_unlock(&tegra_cpu_lock); @@ -712,7 +724,7 @@ static int tegra_pm_notify(struct notifier_block *nb, unsigned long event, unsigned int freq; is_suspended = false; tegra_cpu_edp_init(true); - tegra_cpu_set_speed_cap(&freq); + tegra_cpu_set_speed_cap_locked(&freq); pr_info("Tegra cpufreq resume: restoring frequency to %d kHz\n", freq); } @@ -844,7 +856,9 @@ static int __init tegra_cpufreq_init(void) return ret; freq_table = table_data->freq_table; + mutex_lock(&tegra_cpu_lock); tegra_cpu_edp_init(false); + mutex_unlock(&tegra_cpu_lock); ret = register_pm_notifier(&tegra_cpu_pm_notifier); diff --git a/arch/arm/mach-tegra/cpu-tegra.h b/arch/arm/mach-tegra/cpu-tegra.h index 749ec6345cfa..84504bb0ccc1 100644 --- a/arch/arm/mach-tegra/cpu-tegra.h +++ b/arch/arm/mach-tegra/cpu-tegra.h @@ -1,7 +1,7 @@ /* * arch/arm/mach-tegra/cpu-tegra.h * - * Copyright (c) 2011-2012, NVIDIA Corporation. + * Copyright (c) 2011-2013, NVIDIA Corporation. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -27,6 +27,7 @@ unsigned int tegra_getspeed(unsigned int cpu); int tegra_update_cpu_speed(unsigned long rate); int tegra_cpu_set_speed_cap(unsigned int *speed_cap); +int tegra_cpu_set_speed_cap_locked(unsigned int *speed_cap); void tegra_cpu_set_volt_cap(unsigned int cap); unsigned int tegra_count_slow_cpus(unsigned long speed_limit); unsigned int tegra_get_slowest_cpu_n(void); diff --git a/arch/arm/mach-tegra/cpu-tegra3.c b/arch/arm/mach-tegra/cpu-tegra3.c index f26f449b482b..d7d0250e424e 100644 --- a/arch/arm/mach-tegra/cpu-tegra3.c +++ b/arch/arm/mach-tegra/cpu-tegra3.c @@ -3,7 +3,7 @@ * * CPU auto-hotplug for Tegra3 CPUs * - * Copyright (c) 2011-2012, NVIDIA Corporation. All rights reserved. + * Copyright (c) 2011-2013, NVIDIA Corporation. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -43,6 +43,7 @@ #define UP2Gn_DELAY_MS 100 #define DOWN_DELAY_MS 2000 +/* tegra3_cpu_lock is tegra_cpu_lock from cpu-tegra.c */ static struct mutex *tegra3_cpu_lock; static struct workqueue_struct *hotplug_wq; @@ -160,7 +161,7 @@ static int hp_state_set(const char *arg, const struct kernel_param *kp) hp_init_stats(); } /* catch-up with governor target speed */ - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); } } else pr_warn("%s: unable to set tegra hotplug state %s\n", @@ -295,7 +296,7 @@ static void __cpuinit tegra_auto_hotplug_work_func(struct work_struct *work) hp_stats_update(CONFIG_NR_CPUS, true); hp_stats_update(0, false); /* catch-up with governor target speed */ - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); break; } } @@ -309,7 +310,7 @@ static void __cpuinit tegra_auto_hotplug_work_func(struct work_struct *work) hp_stats_update(CONFIG_NR_CPUS, false); hp_stats_update(0, true); /* catch-up with governor target speed */ - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); } } else { switch (tegra_cpu_speed_balance()) { @@ -373,7 +374,7 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p) } } /* update governor state machine */ - tegra_cpu_set_speed_cap(NULL); + tegra_cpu_set_speed_cap_locked(NULL); mutex_unlock(tegra3_cpu_lock); return NOTIFY_OK; } diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c index a617fa262f46..a66cd52f435f 100644 --- a/arch/arm/mach-tegra/cpuquiet.c +++ b/arch/arm/mach-tegra/cpuquiet.c @@ -3,7 +3,7 @@ * * Cpuquiet driver for Tegra CPUs * - * Copyright (c) 2012 NVIDIA CORPORATION. All rights reserved. + * Copyright (c) 2012-2013 NVIDIA CORPORATION. All rights reserved. * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by @@ -371,6 +371,7 @@ static void __cpuinit tegra_cpuquiet_work_func(struct work_struct *work) current_cluster = __apply_cluster_config(current_cluster, new_cluster); + tegra_cpu_set_speed_cap_locked(NULL); mutex_unlock(tegra_cpu_lock); if (current_cluster == TEGRA_CPQ_LP) @@ -378,9 +379,9 @@ static void __cpuinit tegra_cpuquiet_work_func(struct work_struct *work) else cpuquiet_device_free(); - tegra_cpu_set_speed_cap(NULL); - } else + } else { mutex_unlock(tegra_cpu_lock); + } if (current_cluster == TEGRA_CPQ_G) __apply_core_config(); diff --git a/arch/arm/mach-tegra/tegra3_throttle.c b/arch/arm/mach-tegra/tegra3_throttle.c index 62ba41b5b79d..90ab7c4b6dec 100644 --- a/arch/arm/mach-tegra/tegra3_throttle.c +++ b/arch/arm/mach-tegra/tegra3_throttle.c @@ -33,6 +33,7 @@ #include "clock.h" #include "cpu-tegra.h" +/* cpu_throttle_lock is tegra_cpu_lock from cpu-tegra.c */ static struct mutex *cpu_throttle_lock; static DEFINE_MUTEX(bthrot_list_lock); static LIST_HEAD(bthrot_list); @@ -218,9 +219,7 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev, if (cur_state == 0) { tegra_throttle_cap_freqs_update(NULL, -1, 1);/* uncap freqs */ - mutex_lock(cpu_throttle_lock); tegra_cpu_set_speed_cap(NULL); - mutex_unlock(cpu_throttle_lock); } else { if (cur_state == 1 && direction == 0) bthrot->throttle_count++; @@ -234,9 +233,7 @@ tegra_throttle_set_cur_state(struct thermal_cooling_device *cdev, bthrot->cpu_cap_freq = bthrot->throt_tab[index].cap_freqs[0]; - mutex_lock(cpu_throttle_lock); tegra_cpu_set_speed_cap(NULL); - mutex_unlock(cpu_throttle_lock); } } |