diff options
Diffstat (limited to 'drivers/cpufreq/cpufreq_interactive.c')
-rw-r--r-- | drivers/cpufreq/cpufreq_interactive.c | 334 |
1 files changed, 106 insertions, 228 deletions
diff --git a/drivers/cpufreq/cpufreq_interactive.c b/drivers/cpufreq/cpufreq_interactive.c index baf4326e84c4..cf6ba6c1958e 100644 --- a/drivers/cpufreq/cpufreq_interactive.c +++ b/drivers/cpufreq/cpufreq_interactive.c @@ -30,8 +30,6 @@ #include <asm/cputime.h> -static atomic_t active_count = ATOMIC_INIT(0); - struct cpufreq_interactive_cpuinfo { struct timer_list cpu_timer; int timer_idlecancel; @@ -43,6 +41,7 @@ struct cpufreq_interactive_cpuinfo { u64 freq_change_time; u64 freq_change_time_in_idle; u64 freq_change_time_in_iowait; + u64 last_high_freq_time; struct cpufreq_policy *policy; struct cpufreq_frequency_table *freq_table; unsigned int target_freq; @@ -60,6 +59,9 @@ static spinlock_t up_cpumask_lock; static cpumask_t down_cpumask; static spinlock_t down_cpumask_lock; static struct mutex set_speed_lock; +static struct mutex gov_state_lock; +static struct kobject *interactive_kobj; +static unsigned int active_count; /* Go to max speed when CPU load at or above this value. */ #define DEFAULT_GO_MAXSPEED_LOAD 85 @@ -92,6 +94,24 @@ static unsigned long min_sample_time; #define DEFAULT_TIMER_RATE 20000; static unsigned long timer_rate; +/* + * The minimum delay before frequency is allowed to raise over normal rate. + * Since it must remain at high frequency for a minimum of MIN_SAMPLE_TIME + * once it rises, setting this delay to a multiple of MIN_SAMPLE_TIME + * becomes the best way to enforce a square wave. + * e.g. 5*MIN_SAMPLE_TIME = 20% high freq duty cycle + */ +#define DEFAULT_HIGH_FREQ_MIN_DELAY 5*DEFAULT_MIN_SAMPLE_TIME +static unsigned long high_freq_min_delay; + +/* + * The maximum frequency CPUs are allowed to run normally + * 0 if disabled + */ +#define DEFAULT_MAX_NORMAL_FREQ 0 +static unsigned long max_normal_freq; + + /* Defines to control mid-range frequencies */ #define DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD 95 @@ -274,6 +294,20 @@ static void cpufreq_interactive_timer(unsigned long data) goto rearm; } + /* + * Can only overclock if the delay is satisfy. Otherwise, cap it to + * maximum allowed normal frequency + */ + if (max_normal_freq && (new_freq > max_normal_freq)) { + if (cputime64_sub(pcpu->timer_run_time, pcpu->last_high_freq_time) + < high_freq_min_delay) { + new_freq = max_normal_freq; + } + else { + pcpu->last_high_freq_time = pcpu->timer_run_time; + } + } + if (new_freq < pcpu->target_freq) { pcpu->target_freq = new_freq; spin_lock_irqsave(&down_cpumask_lock, flags); @@ -520,220 +554,43 @@ static void cpufreq_interactive_freq_down(struct work_struct *work) } } -static ssize_t show_go_maxspeed_load(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", go_maxspeed_load); -} - -static ssize_t store_go_maxspeed_load(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - go_maxspeed_load = val; - return count; -} - -static struct global_attr go_maxspeed_load_attr = __ATTR(go_maxspeed_load, 0644, - show_go_maxspeed_load, store_go_maxspeed_load); - -static ssize_t show_midrange_freq(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", midrange_freq); -} - -static ssize_t store_midrange_freq(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - midrange_freq = val; - return count; -} - -static struct global_attr midrange_freq_attr = __ATTR(midrange_freq, 0644, - show_midrange_freq, store_midrange_freq); - -static ssize_t show_midrange_go_maxspeed_load(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", midrange_go_maxspeed_load); -} - -static ssize_t store_midrange_go_maxspeed_load(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - midrange_go_maxspeed_load = val; - return count; -} - -static struct global_attr midrange_go_maxspeed_load_attr = __ATTR(midrange_go_maxspeed_load, 0644, - show_midrange_go_maxspeed_load, store_midrange_go_maxspeed_load); - -static ssize_t show_boost_factor(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", boost_factor); -} - -static ssize_t store_boost_factor(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - boost_factor = val; - return count; -} - -static struct global_attr boost_factor_attr = __ATTR(boost_factor, 0644, - show_boost_factor, store_boost_factor); - -static ssize_t show_io_is_busy(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", io_is_busy); -} - -static ssize_t store_io_is_busy(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - if (!strict_strtoul(buf, 0, &io_is_busy)) - return count; - return -EINVAL; -} - -static struct global_attr io_is_busy_attr = __ATTR(io_is_busy, 0644, - show_io_is_busy, store_io_is_busy); - -static ssize_t show_max_boost(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", max_boost); -} - -static ssize_t store_max_boost(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - max_boost = val; - return count; -} - -static struct global_attr max_boost_attr = __ATTR(max_boost, 0644, - show_max_boost, store_max_boost); - -static ssize_t show_midrange_max_boost(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", midrange_max_boost); -} - -static ssize_t store_midrange_max_boost(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - midrange_max_boost = val; - return count; -} - -static struct global_attr midrange_max_boost_attr = __ATTR(midrange_max_boost, 0644, - show_midrange_max_boost, store_midrange_max_boost); - -static ssize_t show_sustain_load(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", sustain_load); -} - -static ssize_t store_sustain_load(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - sustain_load = val; - return count; -} - -static struct global_attr sustain_load_attr = __ATTR(sustain_load, 0644, - show_sustain_load, store_sustain_load); - -static ssize_t show_min_sample_time(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", min_sample_time); -} - -static ssize_t store_min_sample_time(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - min_sample_time = val; - return count; -} - -static struct global_attr min_sample_time_attr = __ATTR(min_sample_time, 0644, - show_min_sample_time, store_min_sample_time); - -static ssize_t show_timer_rate(struct kobject *kobj, - struct attribute *attr, char *buf) -{ - return sprintf(buf, "%lu\n", timer_rate); -} - -static ssize_t store_timer_rate(struct kobject *kobj, - struct attribute *attr, const char *buf, size_t count) -{ - int ret; - unsigned long val; - - ret = strict_strtoul(buf, 0, &val); - if (ret < 0) - return ret; - timer_rate = val; - return count; -} - -static struct global_attr timer_rate_attr = __ATTR(timer_rate, 0644, - show_timer_rate, store_timer_rate); +#define DECL_CPUFREQ_INTERACTIVE_ATTR(name) \ +static ssize_t show_##name(struct kobject *kobj, \ + struct attribute *attr, char *buf) \ +{ \ + return sprintf(buf, "%lu\n", name); \ +} \ +\ +static ssize_t store_##name(struct kobject *kobj,\ + struct attribute *attr, const char *buf, size_t count) \ +{ \ + int ret; \ + unsigned long val; \ +\ + ret = strict_strtoul(buf, 0, &val); \ + if (ret < 0) \ + return ret; \ + name = val; \ + return count; \ +} \ +\ +static struct global_attr name##_attr = __ATTR(name, 0644, \ + show_##name, store_##name); + +DECL_CPUFREQ_INTERACTIVE_ATTR(go_maxspeed_load) +DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_freq) +DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_go_maxspeed_load) +DECL_CPUFREQ_INTERACTIVE_ATTR(boost_factor) +DECL_CPUFREQ_INTERACTIVE_ATTR(io_is_busy) +DECL_CPUFREQ_INTERACTIVE_ATTR(max_boost) +DECL_CPUFREQ_INTERACTIVE_ATTR(midrange_max_boost) +DECL_CPUFREQ_INTERACTIVE_ATTR(sustain_load) +DECL_CPUFREQ_INTERACTIVE_ATTR(min_sample_time) +DECL_CPUFREQ_INTERACTIVE_ATTR(timer_rate) +DECL_CPUFREQ_INTERACTIVE_ATTR(high_freq_min_delay) +DECL_CPUFREQ_INTERACTIVE_ATTR(max_normal_freq) + +#undef DECL_CPUFREQ_INTERACTIVE_ATTR static struct attribute *interactive_attributes[] = { &go_maxspeed_load_attr.attr, @@ -746,6 +603,8 @@ static struct attribute *interactive_attributes[] = { &sustain_load_attr.attr, &min_sample_time_attr.attr, &timer_rate_attr.attr, + &high_freq_min_delay_attr.attr, + &max_normal_freq_attr.attr, NULL, }; @@ -783,7 +642,8 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, pcpu->freq_change_time_in_iowait = get_cpu_iowait_time(j, NULL); pcpu->time_in_iowait = pcpu->freq_change_time_in_iowait; - + if (!pcpu->last_high_freq_time) + pcpu->last_high_freq_time = pcpu->freq_change_time; pcpu->timer_idlecancel = 1; pcpu->governor_enabled = 1; smp_wmb(); @@ -792,17 +652,25 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, mod_timer(&pcpu->cpu_timer, jiffies + 2); } + mutex_lock(&gov_state_lock); + active_count++; /* * Do not register the idle hook and create sysfs * entries if we have already done so. */ - if (atomic_inc_return(&active_count) > 1) - return 0; - - rc = sysfs_create_group(cpufreq_global_kobject, - &interactive_attr_group); - if (rc) - return rc; + if (active_count == 1) { + rc = sysfs_create_group(cpufreq_global_kobject, + &interactive_attr_group); + interactive_kobj = kobject_create_and_add( + "gov_interactive", + cpufreq_global_kobject); + kobject_uevent(interactive_kobj, KOBJ_ADD); + if (rc) { + mutex_unlock(&gov_state_lock); + return rc; + } + } + mutex_unlock(&gov_state_lock); break; @@ -823,11 +691,18 @@ static int cpufreq_governor_interactive(struct cpufreq_policy *policy, } flush_work(&freq_scale_down_work); - if (atomic_dec_return(&active_count) > 0) - return 0; + mutex_lock(&gov_state_lock); + + active_count--; + + if (active_count == 0) { + sysfs_remove_group(cpufreq_global_kobject, + &interactive_attr_group); + kobject_uevent(interactive_kobj, KOBJ_REMOVE); + kobject_put(interactive_kobj); + } - sysfs_remove_group(cpufreq_global_kobject, - &interactive_attr_group); + mutex_unlock(&gov_state_lock); break; @@ -873,6 +748,8 @@ static int __init cpufreq_interactive_init(void) midrange_go_maxspeed_load = DEFAULT_MID_RANGE_GO_MAXSPEED_LOAD; min_sample_time = DEFAULT_MIN_SAMPLE_TIME; timer_rate = DEFAULT_TIMER_RATE; + high_freq_min_delay = DEFAULT_HIGH_FREQ_MIN_DELAY; + max_normal_freq = DEFAULT_MAX_NORMAL_FREQ; /* Initalize per-cpu timers */ for_each_possible_cpu(i) { @@ -903,6 +780,7 @@ static int __init cpufreq_interactive_init(void) spin_lock_init(&up_cpumask_lock); spin_lock_init(&down_cpumask_lock); mutex_init(&set_speed_lock); + mutex_init(&gov_state_lock); idle_notifier_register(&cpufreq_interactive_idle_nb); |