summaryrefslogtreecommitdiff
path: root/arch/arm/mach-tegra/cpuquiet.c
diff options
context:
space:
mode:
Diffstat (limited to 'arch/arm/mach-tegra/cpuquiet.c')
-rw-r--r--arch/arm/mach-tegra/cpuquiet.c32
1 files changed, 28 insertions, 4 deletions
diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c
index 26adce230920..87aebfe7badb 100644
--- a/arch/arm/mach-tegra/cpuquiet.c
+++ b/arch/arm/mach-tegra/cpuquiet.c
@@ -134,7 +134,7 @@ static void apply_core_config(void)
static void tegra_cpuquiet_work_func(struct work_struct *work)
{
- bool update_cr_config = false;
+ int device_busy = -1;
mutex_lock(tegra3_cpu_lock);
@@ -148,7 +148,7 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
/*catch-up with governor target speed */
tegra_cpu_set_speed_cap(NULL);
/* process pending core requests*/
- update_cr_config = true;
+ device_busy = 0;
}
}
break;
@@ -159,6 +159,7 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
if (!clk_set_parent(cpu_clk, cpu_lp_clk)) {
/*catch-up with governor target speed*/
tegra_cpu_set_speed_cap(NULL);
+ device_busy = 1;
}
}
break;
@@ -169,8 +170,12 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
mutex_unlock(tegra3_cpu_lock);
- if (update_cr_config)
+ if (device_busy == 1) {
+ cpuquiet_device_busy();
+ } else if (!device_busy) {
apply_core_config();
+ cpuquiet_device_free();
+ }
}
static void min_max_constraints_workfunc(struct work_struct *work)
@@ -183,6 +188,9 @@ static void min_max_constraints_workfunc(struct work_struct *work)
int max_cpus = pm_qos_request(PM_QOS_MAX_ONLINE_CPUS) ? : 4;
int min_cpus = pm_qos_request(PM_QOS_MIN_ONLINE_CPUS);
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return;
+
if (is_lp_cluster())
return;
@@ -212,15 +220,22 @@ static void min_max_constraints_workfunc(struct work_struct *work)
static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
+ bool g_cluster = false;
+
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return NOTIFY_OK;
+
mutex_lock(tegra3_cpu_lock);
if ((n >= 1) && is_lp_cluster()) {
- /* make sure cpu rate is within g-mode range before switching */
+ /* make sure cpu rate is within g-mode
+ * range before switching */
unsigned long speed = max((unsigned long)tegra_getspeed(0),
clk_get_min_rate(cpu_g_clk) / 1000);
tegra_update_cpu_speed(speed);
clk_set_parent(cpu_clk, cpu_g_clk);
+ g_cluster = true;
}
tegra_cpu_set_speed_cap(NULL);
@@ -228,11 +243,17 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
schedule_work(&minmax_work);
+ if (g_cluster)
+ cpuquiet_device_free();
+
return NOTIFY_OK;
}
static int max_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
{
+ if (cpq_state == TEGRA_CPQ_DISABLED)
+ return NOTIFY_OK;
+
if (n < num_online_cpus())
schedule_work(&minmax_work);
@@ -253,6 +274,7 @@ void tegra_auto_hotplug_governor(unsigned int cpu_freq, bool suspend)
/* Switch to G-mode if suspend rate is high enough */
if (is_lp_cluster() && (cpu_freq >= idle_bottom_freq)) {
clk_set_parent(cpu_clk, cpu_g_clk);
+ cpuquiet_device_free();
}
return;
}
@@ -306,11 +328,13 @@ static void enable_callback(struct cpuquiet_attribute *attr)
mutex_unlock(tegra3_cpu_lock);
cancel_delayed_work_sync(&cpuquiet_work);
pr_info("Tegra cpuquiet clusterswitch disabled\n");
+ cpuquiet_device_busy();
mutex_lock(tegra3_cpu_lock);
} else if (enable && cpq_state == TEGRA_CPQ_DISABLED) {
cpq_state = TEGRA_CPQ_IDLE;
pr_info("Tegra cpuquiet clusterswitch enabled\n");
tegra_cpu_set_speed_cap(NULL);
+ cpuquiet_device_free();
}
mutex_unlock(tegra3_cpu_lock);