summaryrefslogtreecommitdiff
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
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
-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 */