summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpu-tegra.c
diff options
context:
space:
mode:
authorAlex Frid <afrid@nvidia.com>2011-07-09 23:22:12 -0700
committerDan Willemsen <dwillemsen@nvidia.com>2011-11-30 21:47:49 -0800
commit2b36b250e164643205e9a182f6e1e28aed2c1b80 (patch)
tree36194265094a6e1e479852677661bcd43b0ec0e1 /arch/arm/mach-tegra/cpu-tegra.c
parentec8491e25fe2d34a991b42463aea0472a0c85b9b (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 Original-Change-Id: If2aa8aa16f4a3b3497def592503213522fd38e54 Reviewed-on: http://git-master/r/40534 Reviewed-by: Varun Colbert <vcolbert@nvidia.com> Tested-by: Varun Colbert <vcolbert@nvidia.com> Rebase-Id: R893b5a7b402d327b40acb7adbadb53f930804c0d
Diffstat (limited to 'arch/arm/mach-tegra/cpu-tegra.c')
-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 746add6661d6..aa2e5720b459 100644
--- a/arch/arm/mach-tegra/cpu-tegra.c
+++ b/arch/arm/mach-tegra/cpu-tegra.c
@@ -60,21 +60,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;
@@ -85,7 +87,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);
}
@@ -95,13 +97,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--)
@@ -113,19 +114,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;
}
@@ -181,7 +187,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 */