diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq_pegasusq.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_pegasusq.c | 95 |
1 files changed, 90 insertions, 5 deletions
diff --git a/drivers/cpufreq/cpufreq_pegasusq.c b/drivers/cpufreq/cpufreq_pegasusq.c index 4a90a01..208a991 100644 --- a/drivers/cpufreq/cpufreq_pegasusq.c +++ b/drivers/cpufreq/cpufreq_pegasusq.c @@ -34,6 +34,7 @@ #ifdef CONFIG_HAS_EARLYSUSPEND #include <linux/earlysuspend.h> #endif +#define EARLYSUSPEND_HOTPLUGLOCK 1 /* * runqueue average @@ -154,16 +155,17 @@ static unsigned int get_nr_run_avg(void) #define MAX_HOTPLUG_RATE (40u) #define DEF_MAX_CPU_LOCK (0) +#define DEF_MIN_CPU_LOCK (0) #define DEF_CPU_UP_FREQ (500000) #define DEF_CPU_DOWN_FREQ (200000) #define DEF_UP_NR_CPUS (1) #define DEF_CPU_UP_RATE (10) #define DEF_CPU_DOWN_RATE (20) -#define DEF_FREQ_STEP (40) +#define DEF_FREQ_STEP (37) #define DEF_START_DELAY (0) #define UP_THRESHOLD_AT_MIN_FREQ (40) -#define FREQ_FOR_RESPONSIVENESS (500000) +#define FREQ_FOR_RESPONSIVENESS (400000) #define HOTPLUG_DOWN_INDEX (0) #define HOTPLUG_UP_INDEX (1) @@ -255,6 +257,7 @@ static struct dbs_tuners { unsigned int cpu_down_freq; unsigned int up_nr_cpus; unsigned int max_cpu_lock; + unsigned int min_cpu_lock; atomic_t hotplug_lock; unsigned int dvfs_debug; unsigned int max_freq; @@ -274,6 +277,7 @@ static struct dbs_tuners { .cpu_down_freq = DEF_CPU_DOWN_FREQ, .up_nr_cpus = DEF_UP_NR_CPUS, .max_cpu_lock = DEF_MAX_CPU_LOCK, + .min_cpu_lock = DEF_MIN_CPU_LOCK, .hotplug_lock = ATOMIC_INIT(0), .dvfs_debug = 0, #ifdef CONFIG_HAS_EARLYSUSPEND @@ -349,6 +353,38 @@ int cpufreq_pegasusq_cpu_unlock(int num_core) return 0; } +void cpufreq_pegasusq_min_cpu_lock(unsigned int num_core) +{ + int online, flag; + struct cpu_dbs_info_s *dbs_info; + + dbs_tuners_ins.min_cpu_lock = min(num_core, num_possible_cpus()); + + dbs_info = &per_cpu(od_cpu_dbs_info, 0); /* from CPU0 */ + online = num_online_cpus(); + flag = (int)num_core - online; + if (flag <= 0) + return; + queue_work_on(dbs_info->cpu, dvfs_workqueue, &dbs_info->up_work); +} + +void cpufreq_pegasusq_min_cpu_unlock(void) +{ + int online, lock, flag; + struct cpu_dbs_info_s *dbs_info; + + dbs_tuners_ins.min_cpu_lock = 0; + + dbs_info = &per_cpu(od_cpu_dbs_info, 0); /* from CPU0 */ + online = num_online_cpus(); + lock = atomic_read(&g_hotplug_lock); + if (lock == 0) + return; + flag = lock - online; + if (flag >= 0) + return; + queue_work_on(dbs_info->cpu, dvfs_workqueue, &dbs_info->down_work); +} /* * History of CPU usage @@ -440,6 +476,7 @@ show_one(cpu_up_freq, cpu_up_freq); show_one(cpu_down_freq, cpu_down_freq); show_one(up_nr_cpus, up_nr_cpus); show_one(max_cpu_lock, max_cpu_lock); +show_one(min_cpu_lock, min_cpu_lock); show_one(dvfs_debug, dvfs_debug); static ssize_t show_hotplug_lock(struct kobject *kobj, struct attribute *attr, char *buf) @@ -700,6 +737,21 @@ static ssize_t store_max_cpu_lock(struct kobject *a, struct attribute *b, return count; } +static ssize_t store_min_cpu_lock(struct kobject *a, struct attribute *b, + const char *buf, size_t count) +{ + unsigned int input; + int ret; + ret = sscanf(buf, "%u", &input); + if (ret != 1) + return -EINVAL; + if (input == 0) + cpufreq_pegasusq_min_cpu_unlock(); + else + cpufreq_pegasusq_min_cpu_lock(input); + return count; +} + static ssize_t store_hotplug_lock(struct kobject *a, struct attribute *b, const char *buf, size_t count) { @@ -758,6 +810,7 @@ define_one_global_rw(cpu_up_freq); define_one_global_rw(cpu_down_freq); define_one_global_rw(up_nr_cpus); define_one_global_rw(max_cpu_lock); +define_one_global_rw(min_cpu_lock); define_one_global_rw(hotplug_lock); define_one_global_rw(dvfs_debug); @@ -775,8 +828,10 @@ static struct attribute *dbs_attributes[] = { &cpu_up_freq.attr, &cpu_down_freq.attr, &up_nr_cpus.attr, - /* priority: hotplug_lock > max_cpu_lock */ + /* priority: hotplug_lock > max_cpu_lock > min_cpu_lock + Exception: hotplug_lock on early_suspend uses min_cpu_lock */ &max_cpu_lock.attr, + &min_cpu_lock.attr, &hotplug_lock.attr, &dvfs_debug.attr, &hotplug_freq_1_1.attr, @@ -806,9 +861,15 @@ static void cpu_up_work(struct work_struct *work) int cpu; int online = num_online_cpus(); int nr_up = dbs_tuners_ins.up_nr_cpus; + int min_cpu_lock = dbs_tuners_ins.min_cpu_lock; int hotplug_lock = atomic_read(&g_hotplug_lock); - if (hotplug_lock) + + if (hotplug_lock && min_cpu_lock) + nr_up = max(hotplug_lock, min_cpu_lock) - online; + else if (hotplug_lock) nr_up = hotplug_lock - online; + else if (min_cpu_lock) + nr_up = max(nr_up, min_cpu_lock - online); if (online == 1) { printk(KERN_ERR "CPU_UP 3\n"); @@ -894,10 +955,15 @@ static int check_up(void) if (online == num_possible_cpus()) return 0; + if (dbs_tuners_ins.max_cpu_lock != 0 && online >= dbs_tuners_ins.max_cpu_lock) return 0; + if (dbs_tuners_ins.min_cpu_lock != 0 + && online < dbs_tuners_ins.min_cpu_lock) + return 1; + if (num_hist == 0 || num_hist % up_rate) return 0; @@ -950,6 +1016,10 @@ static int check_down(void) && online > dbs_tuners_ins.max_cpu_lock) return 1; + if (dbs_tuners_ins.min_cpu_lock != 0 + && online <= dbs_tuners_ins.min_cpu_lock) + return 0; + if (num_hist == 0 || num_hist % down_rate) return 0; @@ -1221,24 +1291,33 @@ unsigned int prev_freq_step; unsigned int prev_sampling_rate; static void cpufreq_pegasusq_early_suspend(struct early_suspend *h) { +#if EARLYSUSPEND_HOTPLUGLOCK dbs_tuners_ins.early_suspend = atomic_read(&g_hotplug_lock); +#endif prev_freq_step = dbs_tuners_ins.freq_step; prev_sampling_rate = dbs_tuners_ins.sampling_rate; dbs_tuners_ins.freq_step = 20; dbs_tuners_ins.sampling_rate *= 4; - atomic_set(&g_hotplug_lock, 1); +#if EARLYSUSPEND_HOTPLUGLOCK + atomic_set(&g_hotplug_lock, + (dbs_tuners_ins.min_cpu_lock) ? dbs_tuners_ins.min_cpu_lock : 1); apply_hotplug_lock(); stop_rq_work(); +#endif } static void cpufreq_pegasusq_late_resume(struct early_suspend *h) { +#if EARLYSUSPEND_HOTPLUGLOCK atomic_set(&g_hotplug_lock, dbs_tuners_ins.early_suspend); +#endif dbs_tuners_ins.early_suspend = -1; dbs_tuners_ins.freq_step = prev_freq_step; dbs_tuners_ins.sampling_rate = prev_sampling_rate; +#if EARLYSUSPEND_HOTPLUGLOCK apply_hotplug_lock(); start_rq_work(); +#endif } #endif @@ -1302,6 +1381,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, mutex_init(&this_dbs_info->timer_mutex); dbs_timer_init(this_dbs_info); +#if !EARLYSUSPEND_HOTPLUGLOCK + register_pm_notifier(&pm_notifier); +#endif #ifdef CONFIG_HAS_EARLYSUSPEND register_early_suspend(&early_suspend); #endif @@ -1311,6 +1393,9 @@ static int cpufreq_governor_dbs(struct cpufreq_policy *policy, #ifdef CONFIG_HAS_EARLYSUSPEND unregister_early_suspend(&early_suspend); #endif +#if !EARLYSUSPEND_HOTPLUGLOCK + unregister_pm_notifier(&pm_notifier); +#endif dbs_timer_exit(this_dbs_info); |