summaryrefslogtreecommitdiff
path: root/arch
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-07-09 23:22:12 -0700
committerVarun Colbert <vcolbert@nvidia.com>2011-07-22 17:35:22 -0700
commit7448aa61651f6c105ec08f64458b2ec2e5e05bf6 (patch)
treea5916d1849f1f8cf70392cd51d9163b33357d660 /arch
parenta0d977ac86e67a584a1988d8a3be8b6ee76914e1 (diff)
ARM: tegra: power: Add throttling enable reference counting
Added throttling enable reference counting, so that it can be controlled by drivers for different thermal sensors (e.g, on chip and device skin sensors). Fixed possible dead-lock when cancel delayed work synchronous is called while locked with the very same mutex that protects work function. Bug 837005 Change-Id: If2aa8aa16f4a3b3497def592503213522fd38e54 Reviewed-on: http://git-master/r/40534 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com>
Diffstat (limited to 'arch')
-rw-r--r--arch/arm/mach-tegra/cpu-tegra.c33
1 files changed, 19 insertions, 14 deletions
diff --git a/arch/arm/mach-tegra/cpu-tegra.c b/arch/arm/mach-tegra/cpu-tegra.c
index 52b5a7583663..313de98583a1 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -62,21 +62,23 @@ unsigned int tegra_getspeed(unsigned int cpu);
/* CPU frequency is gradually lowered when throttling is enabled */
#define THROTTLE_DELAY msecs_to_jiffies(2000)
-static bool is_throttling;
+static int is_throttling;
static int throttle_lowest_index;
static int throttle_highest_index;
static int throttle_index;
static int throttle_next_index;
static struct delayed_work throttle_work;
static struct workqueue_struct *workqueue;
-
-#define tegra_cpu_is_throttling() (is_throttling)
+static DEFINE_MUTEX(tegra_throttle_lock);
static void tegra_throttle_work_func(struct work_struct *work)
{
unsigned int current_freq;
mutex_lock(&tegra_cpu_lock);
+ if (!is_throttling)
+ goto out;
+
current_freq = tegra_getspeed(0);
throttle_index = throttle_next_index;
@@ -87,7 +89,7 @@ static void tegra_throttle_work_func(struct work_struct *work)
throttle_next_index = throttle_index - 1;
queue_delayed_work(workqueue, &throttle_work, THROTTLE_DELAY);
}
-
+out:
mutex_unlock(&tegra_cpu_lock);
}
@@ -97,13 +99,12 @@ static void tegra_throttle_work_func(struct work_struct *work)
*/
void tegra_throttling_enable(bool enable)
{
+ mutex_lock(&tegra_throttle_lock);
mutex_lock(&tegra_cpu_lock);
- if (enable && !is_throttling) {
+ if (enable && !(is_throttling++)) {
unsigned int current_freq = tegra_getspeed(0);
- is_throttling = true;
-
for (throttle_index = throttle_highest_index;
throttle_index >= throttle_lowest_index;
throttle_index--)
@@ -115,19 +116,24 @@ void tegra_throttling_enable(bool enable)
throttle_next_index = throttle_index;
queue_delayed_work(workqueue, &throttle_work, 0);
} else if (!enable && is_throttling) {
- cancel_delayed_work_sync(&throttle_work);
- is_throttling = false;
- /* restore speed requested by governor */
- tegra_cpu_set_speed_cap(NULL);
+ if (!(--is_throttling)) {
+ /* restore speed requested by governor */
+ tegra_cpu_set_speed_cap(NULL);
+
+ mutex_unlock(&tegra_cpu_lock);
+ cancel_delayed_work_sync(&throttle_work);
+ mutex_unlock(&tegra_throttle_lock);
+ return;
+ }
}
-
mutex_unlock(&tegra_cpu_lock);
+ mutex_unlock(&tegra_throttle_lock);
}
EXPORT_SYMBOL_GPL(tegra_throttling_enable);
static unsigned int throttle_governor_speed(unsigned int requested_speed)
{
- return tegra_cpu_is_throttling() ?
+ return is_throttling ?
min(requested_speed, freq_table[throttle_index].frequency) :
requested_speed;
}
@@ -183,7 +189,6 @@ module_exit(tegra_cpu_debug_exit);
#endif /* CONFIG_DEBUG_FS */
#else /* CONFIG_TEGRA_THERMAL_THROTTLE */
-#define tegra_cpu_is_throttling() (0)
#define throttle_governor_speed(requested_speed) (requested_speed)
#endif /* CONFIG_TEGRA_THERMAL_THROTTLE */