diff options
-rw-r--r-- | arch/arm/mach-tegra/cpuquiet.c | 20 | ||||
-rw-r--r-- | drivers/cpuquiet/governor.c | 14 | ||||
-rw-r--r-- | include/linux/cpuquiet.h | 4 |
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; |