summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--arch/arm/mach-tegra/cpuquiet.c20
-rw-r--r--drivers/cpuquiet/governor.c14
-rw-r--r--include/linux/cpuquiet.h4
3 files changed, 35 insertions, 3 deletions
diff --git a/arch/arm/mach-tegra/cpuquiet.c b/arch/arm/mach-tegra/cpuquiet.c
index d1d0da2ee839..e449c5ec2819 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;
+ bool state_changed = false;
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;
+ state_changed = true;
}
}
break;
@@ -158,6 +158,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);
+ state_changed = true;
}
}
break;
@@ -168,8 +169,12 @@ static void tegra_cpuquiet_work_func(struct work_struct *work)
mutex_unlock(tegra3_cpu_lock);
- if (update_cr_config)
+ if (state_changed && cpq_state == TEGRA_CPQ_SWITCH_TO_LP) {
+ cpuquiet_device_busy();
+ } else if (state_changed && cpq_state == TEGRA_CPQ_SWITCH_TO_G) {
apply_core_config();
+ cpuquiet_device_free();
+ }
}
static void min_max_constraints_workfunc(struct work_struct *work)
@@ -211,6 +216,8 @@ 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;
+
mutex_lock(tegra3_cpu_lock);
if ((n >= 2) && is_lp_cluster()) {
@@ -220,6 +227,7 @@ static int min_cpus_notify(struct notifier_block *nb, unsigned long n, void *p)
tegra_update_cpu_speed(speed);
clk_set_parent(cpu_clk, cpu_g_clk);
+ g_cluster = true;
}
tegra_cpu_set_speed_cap(NULL);
@@ -227,6 +235,9 @@ 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;
}
@@ -252,6 +263,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;
}
@@ -305,11 +317,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);
diff --git a/drivers/cpuquiet/governor.c b/drivers/cpuquiet/governor.c
index 7895fccc7f42..176ba3bd705f 100644
--- a/drivers/cpuquiet/governor.c
+++ b/drivers/cpuquiet/governor.c
@@ -100,3 +100,17 @@ void cpuquiet_unregister_governor(struct cpuquiet_governor *gov)
list_del(&gov->governor_list);
mutex_unlock(&cpuquiet_lock);
}
+
+void cpuquiet_device_busy(void)
+{
+ if (cpuquiet_curr_governor &&
+ cpuquiet_curr_governor->device_busy_notification)
+ cpuquiet_curr_governor->device_busy_notification();
+}
+
+void cpuquiet_device_free(void)
+{
+ if (cpuquiet_curr_governor &&
+ cpuquiet_curr_governor->device_free_notification)
+ cpuquiet_curr_governor->device_free_notification();
+}
diff --git a/include/linux/cpuquiet.h b/include/linux/cpuquiet.h
index fe5a03727739..5558c015bb50 100644
--- a/include/linux/cpuquiet.h
+++ b/include/linux/cpuquiet.h
@@ -30,6 +30,8 @@ struct cpuquiet_governor {
int (*start) (void);
void (*stop) (void);
int (*store_active) (unsigned int cpu, bool active);
+ void (*device_free_notification) (void);
+ void (*device_busy_notification) (void);
struct module *owner;
};
@@ -47,6 +49,8 @@ extern int cpuquiet_register_driver(struct cpuquiet_driver *drv);
extern void cpuquiet_unregister_driver(struct cpuquiet_driver *drv);
extern int cpuquiet_add_group(struct attribute_group *attrs);
extern void cpuquiet_remove_group(struct attribute_group *attrs);
+extern void cpuquiet_device_busy(void);
+extern void cpuquiet_device_free(void);
int cpuquiet_kobject_init(struct kobject *kobj, struct kobj_type *type,
char *name);
extern unsigned int nr_cluster_ids;