Add smartass governor
This commit is contained in:
parent
19867bdf03
commit
fc0156bf88
@ -111,6 +111,13 @@ config CPU_FREQ_DEFAULT_GOV_CONSERVATIVE
|
||||
governor. If unsure have a look at the help section of the
|
||||
driver. Fallback governor will be the performance governor.
|
||||
|
||||
config CPU_FREQ_DEFAULT_GOV_SMARTASS
|
||||
bool "smartass"
|
||||
select CPU_FREQ_GOV_SMARTASS
|
||||
select CPU_FREQ_GOV_PERFORMANCE
|
||||
help
|
||||
Use the CPUFreq governor 'smartass' as default.
|
||||
|
||||
config CPU_FREQ_DEFAULT_GOV_INTERACTIVE
|
||||
bool "interactive"
|
||||
select CPU_FREQ_GOV_INTERACTIVE
|
||||
@ -213,4 +220,19 @@ config CPU_FREQ_VDD_LEVELS
|
||||
help
|
||||
CPU Vdd levels sysfs interface
|
||||
|
||||
|
||||
config CPU_FREQ_GOV_SMARTASS
|
||||
tristate "'smartass' cpufreq governor"
|
||||
depends on CPU_FREQ
|
||||
help
|
||||
'smartass' - a "smart" optimized governor for the hero!
|
||||
|
||||
If in doubt, say N.
|
||||
|
||||
config CPU_FREQ_MIN_TICKS
|
||||
int "Ticks between governor polling interval."
|
||||
default 10
|
||||
help
|
||||
Minimum number of ticks between polling interval for governors.
|
||||
|
||||
endif # CPU_FREQ
|
||||
|
@ -9,6 +9,7 @@ obj-$(CONFIG_CPU_FREQ_GOV_POWERSAVE) += cpufreq_powersave.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_USERSPACE) += cpufreq_userspace.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_ONDEMAND) += cpufreq_ondemand.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_CONSERVATIVE) += cpufreq_conservative.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_SMARTASS) += cpufreq_smartass.o
|
||||
obj-$(CONFIG_CPU_FREQ_GOV_INTERACTIVE) += cpufreq_interactive.o
|
||||
|
||||
# CPUfreq cross-arch helpers
|
||||
|
589
drivers/cpufreq/cpufreq_smartass.c
Normal file
589
drivers/cpufreq/cpufreq_smartass.c
Normal file
@ -0,0 +1,589 @@
|
||||
/*
|
||||
* drivers/cpufreq/cpufreq_smartass.c
|
||||
*
|
||||
* Copyright (C) 2010 Google, Inc.
|
||||
*
|
||||
* This software is licensed under the terms of the GNU General Public
|
||||
* License version 2, as published by the Free Software Foundation, and
|
||||
* may be copied, distributed, and modified under those terms.
|
||||
*
|
||||
* This program is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*
|
||||
* Author: Erasmux
|
||||
*
|
||||
* Based on the interactive governor By Mike Chan (mike@android.com)
|
||||
* which was adaptated to 2.6.29 kernel by Nadlabak (pavel@doshaska.net)
|
||||
*
|
||||
* requires to add
|
||||
* EXPORT_SYMBOL_GPL(nr_running);
|
||||
* at the end of kernel/sched.c
|
||||
*
|
||||
*/
|
||||
|
||||
#include <linux/cpu.h>
|
||||
#include <linux/cpumask.h>
|
||||
#include <linux/cpufreq.h>
|
||||
#include <linux/sched.h>
|
||||
#include <linux/tick.h>
|
||||
#include <linux/timer.h>
|
||||
#include <linux/workqueue.h>
|
||||
#include <linux/moduleparam.h>
|
||||
#include <asm/cputime.h>
|
||||
#include <linux/earlysuspend.h>
|
||||
|
||||
static void (*pm_idle_old)(void);
|
||||
static atomic_t active_count = ATOMIC_INIT(0);
|
||||
|
||||
struct smartass_info_s {
|
||||
struct cpufreq_policy *cur_policy;
|
||||
struct timer_list timer;
|
||||
u64 time_in_idle;
|
||||
u64 idle_exit_time;
|
||||
unsigned int force_ramp_up;
|
||||
unsigned int enable;
|
||||
};
|
||||
static DEFINE_PER_CPU(struct smartass_info_s, smartass_info);
|
||||
|
||||
/* Workqueues handle frequency scaling */
|
||||
static struct workqueue_struct *up_wq;
|
||||
static struct workqueue_struct *down_wq;
|
||||
static struct work_struct freq_scale_work;
|
||||
|
||||
static u64 freq_change_time;
|
||||
static u64 freq_change_time_in_idle;
|
||||
|
||||
static cpumask_t work_cpumask;
|
||||
static unsigned int suspended;
|
||||
|
||||
/*
|
||||
* The minimum amount of time to spend at a frequency before we can ramp down,
|
||||
* default is 45ms.
|
||||
*/
|
||||
#define DEFAULT_RAMP_DOWN_RATE_NS 45000;
|
||||
static unsigned long ramp_down_rate_ns;
|
||||
|
||||
/*
|
||||
* When ramping up frequency jump to at least this frequency.
|
||||
*/
|
||||
#define DEFAULT_UP_MIN_FREQ CONFIG_MSM_CPU_FREQ_ONDEMAND_MAX
|
||||
static unsigned int up_min_freq;
|
||||
|
||||
/*
|
||||
* When sleep_max_freq>0 the frequency when suspended will be capped
|
||||
* by this frequency. Also will wake up at max frequency of policy
|
||||
* to minimize wakeup issues.
|
||||
* Set sleep_max_freq=0 to disable this behavior.
|
||||
*/
|
||||
#define DEFAULT_SLEEP_MAX_FREQ CONFIG_MSM_CPU_FREQ_ONDEMAND_MIN
|
||||
static unsigned int sleep_max_freq;
|
||||
|
||||
/*
|
||||
* Sampling rate, I highly recommend to leave it at 2.
|
||||
*/
|
||||
#define DEFAULT_SAMPLE_RATE_JIFFIES 2
|
||||
static unsigned int sample_rate_jiffies;
|
||||
|
||||
/*
|
||||
* Max freqeuncy delta when ramping up.
|
||||
*/
|
||||
#define DEFAULT_MAX_RAMP_UP 176000
|
||||
static unsigned int max_ramp_up;
|
||||
|
||||
/*
|
||||
* CPU freq will be increased if measured load > max_cpu_load;
|
||||
*/
|
||||
#define DEFAULT_MAX_CPU_LOAD 80
|
||||
static unsigned long max_cpu_load;
|
||||
|
||||
/*
|
||||
* CPU freq will be decreased if measured load < min_cpu_load;
|
||||
*/
|
||||
#define DEFAULT_MIN_CPU_LOAD 30
|
||||
static unsigned long min_cpu_load;
|
||||
|
||||
|
||||
static int cpufreq_governor_smartass(struct cpufreq_policy *policy,
|
||||
unsigned int event);
|
||||
|
||||
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS
|
||||
static
|
||||
#endif
|
||||
struct cpufreq_governor cpufreq_gov_smartass = {
|
||||
.name = "smartass",
|
||||
.governor = cpufreq_governor_smartass,
|
||||
.max_transition_latency = 9000000,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static void cpufreq_smartass_timer(unsigned long data)
|
||||
{
|
||||
u64 delta_idle;
|
||||
u64 update_time;
|
||||
u64 now_idle;
|
||||
struct smartass_info_s *this_smartass = &per_cpu(smartass_info, data);
|
||||
struct cpufreq_policy *policy = this_smartass->cur_policy;
|
||||
|
||||
now_idle = get_cpu_idle_time_us(data, &update_time);
|
||||
|
||||
if (update_time == this_smartass->idle_exit_time)
|
||||
return;
|
||||
|
||||
delta_idle = cputime64_sub(now_idle, this_smartass->time_in_idle);
|
||||
//printk(KERN_INFO "smartass: t=%llu i=%llu\n",cputime64_sub(update_time,this_smartass->idle_exit_time),delta_idle);
|
||||
|
||||
/* Scale up if there were no idle cycles since coming out of idle */
|
||||
if (delta_idle == 0) {
|
||||
if (policy->cur == policy->max)
|
||||
return;
|
||||
|
||||
if (nr_running() < 1)
|
||||
return;
|
||||
|
||||
this_smartass->force_ramp_up = 1;
|
||||
cpumask_set_cpu(data, &work_cpumask);
|
||||
queue_work(up_wq, &freq_scale_work);
|
||||
return;
|
||||
}
|
||||
|
||||
/*
|
||||
* There is a window where if the cpu utlization can go from low to high
|
||||
* between the timer expiring, delta_idle will be > 0 and the cpu will
|
||||
* be 100% busy, preventing idle from running, and this timer from
|
||||
* firing. So setup another timer to fire to check cpu utlization.
|
||||
* Do not setup the timer if there is no scheduled work.
|
||||
*/
|
||||
if (!timer_pending(&this_smartass->timer) && nr_running() > 0) {
|
||||
this_smartass->time_in_idle = get_cpu_idle_time_us(
|
||||
data, &this_smartass->idle_exit_time);
|
||||
mod_timer(&this_smartass->timer, jiffies + sample_rate_jiffies);
|
||||
}
|
||||
|
||||
if (policy->cur == policy->min)
|
||||
return;
|
||||
|
||||
/*
|
||||
* Do not scale down unless we have been at this frequency for the
|
||||
* minimum sample time.
|
||||
*/
|
||||
if (cputime64_sub(update_time, freq_change_time) < ramp_down_rate_ns)
|
||||
return;
|
||||
|
||||
cpumask_set_cpu(data, &work_cpumask);
|
||||
queue_work(down_wq, &freq_scale_work);
|
||||
}
|
||||
|
||||
static void cpufreq_idle(void)
|
||||
{
|
||||
struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id());
|
||||
struct cpufreq_policy *policy = this_smartass->cur_policy;
|
||||
|
||||
pm_idle_old();
|
||||
|
||||
if (!cpumask_test_cpu(smp_processor_id(), policy->cpus))
|
||||
return;
|
||||
|
||||
/* Timer to fire in 1-2 ticks, jiffie aligned. */
|
||||
if (timer_pending(&this_smartass->timer) == 0) {
|
||||
this_smartass->time_in_idle = get_cpu_idle_time_us(
|
||||
smp_processor_id(), &this_smartass->idle_exit_time);
|
||||
mod_timer(&this_smartass->timer, jiffies + sample_rate_jiffies);
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
* Choose the cpu frequency based off the load. For now choose the minimum
|
||||
* frequency that will satisfy the load, which is not always the lower power.
|
||||
*/
|
||||
static unsigned int cpufreq_smartass_calc_freq(unsigned int cpu, struct cpufreq_policy *policy)
|
||||
{
|
||||
unsigned int delta_time;
|
||||
unsigned int idle_time;
|
||||
unsigned int cpu_load;
|
||||
unsigned int new_freq;
|
||||
u64 current_wall_time;
|
||||
u64 current_idle_time;
|
||||
|
||||
current_idle_time = get_cpu_idle_time_us(cpu, ¤t_wall_time);
|
||||
|
||||
idle_time = (unsigned int)( current_idle_time - freq_change_time_in_idle );
|
||||
delta_time = (unsigned int)( current_wall_time - freq_change_time );
|
||||
|
||||
cpu_load = 100 * (delta_time - idle_time) / delta_time;
|
||||
//printk(KERN_INFO "Smartass calc_freq: delta_time=%u cpu_load=%u\n",delta_time,cpu_load);
|
||||
if (cpu_load < min_cpu_load) {
|
||||
cpu_load += 100 - max_cpu_load; // dummy load.
|
||||
new_freq = policy->cur * cpu_load / 100;
|
||||
//if (new_freq < policy->cur - max_ramp_up) new_freq = policy->cur - max_ramp_up;
|
||||
//printk(KERN_INFO "Smartass calc_freq: %u => %u\n",policy->cur,new_freq);
|
||||
return new_freq;
|
||||
} if (cpu_load > max_cpu_load) {
|
||||
new_freq = policy->cur / max_cpu_load;
|
||||
if (new_freq > policy->cur + max_ramp_up)
|
||||
new_freq = policy->cur + max_ramp_up;
|
||||
return new_freq;
|
||||
}
|
||||
return policy->cur;
|
||||
}
|
||||
|
||||
/* We use the same work function to sale up and down */
|
||||
static void cpufreq_smartass_freq_change_time_work(struct work_struct *work)
|
||||
{
|
||||
unsigned int cpu;
|
||||
unsigned int new_freq;
|
||||
struct smartass_info_s *this_smartass;
|
||||
struct cpufreq_policy *policy;
|
||||
cpumask_t tmp_mask = work_cpumask;
|
||||
for_each_cpu(cpu, tmp_mask) {
|
||||
this_smartass = &per_cpu(smartass_info, cpu);
|
||||
policy = this_smartass->cur_policy;
|
||||
|
||||
if (this_smartass->force_ramp_up) {
|
||||
this_smartass->force_ramp_up = 0;
|
||||
|
||||
if (nr_running() == 1) {
|
||||
cpumask_clear_cpu(cpu, &work_cpumask);
|
||||
return;
|
||||
}
|
||||
|
||||
if (policy->cur == policy->max)
|
||||
return;
|
||||
|
||||
new_freq = policy->cur + max_ramp_up;
|
||||
|
||||
if (suspended && sleep_max_freq) {
|
||||
if (new_freq > sleep_max_freq)
|
||||
new_freq = sleep_max_freq;
|
||||
} else {
|
||||
if (new_freq < up_min_freq)
|
||||
new_freq = up_min_freq;
|
||||
}
|
||||
|
||||
} else {
|
||||
new_freq = cpufreq_smartass_calc_freq(cpu,policy);
|
||||
|
||||
// in suspend limit to sleep_max_freq and
|
||||
// jump straight to sleep_max_freq to avoid wakeup problems
|
||||
if (suspended && sleep_max_freq &&
|
||||
(new_freq > sleep_max_freq || new_freq > policy->cur))
|
||||
new_freq = sleep_max_freq;
|
||||
}
|
||||
|
||||
if (new_freq > policy->max)
|
||||
new_freq = policy->max;
|
||||
|
||||
if (new_freq < policy->min)
|
||||
new_freq = policy->min;
|
||||
|
||||
__cpufreq_driver_target(policy, new_freq,
|
||||
CPUFREQ_RELATION_L);
|
||||
|
||||
freq_change_time_in_idle = get_cpu_idle_time_us(cpu,
|
||||
&freq_change_time);
|
||||
|
||||
cpumask_clear_cpu(cpu, &work_cpumask);
|
||||
}
|
||||
|
||||
|
||||
}
|
||||
|
||||
static ssize_t show_ramp_down_rate_ns(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", ramp_down_rate_ns);
|
||||
}
|
||||
|
||||
static ssize_t store_ramp_down_rate_ns(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input >= 1000 && input <= 100000000)
|
||||
ramp_down_rate_ns = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr ramp_down_rate_ns_attr = __ATTR(ramp_down_rate_ns, 0644,
|
||||
show_ramp_down_rate_ns, store_ramp_down_rate_ns);
|
||||
|
||||
static ssize_t show_up_min_freq(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", up_min_freq);
|
||||
}
|
||||
|
||||
static ssize_t store_up_min_freq(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input >= 0)
|
||||
up_min_freq = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr up_min_freq_attr = __ATTR(up_min_freq, 0644,
|
||||
show_up_min_freq, store_up_min_freq);
|
||||
|
||||
static ssize_t show_sleep_max_freq(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", sleep_max_freq);
|
||||
}
|
||||
|
||||
static ssize_t store_sleep_max_freq(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input >= 0)
|
||||
sleep_max_freq = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr sleep_max_freq_attr = __ATTR(sleep_max_freq, 0644,
|
||||
show_sleep_max_freq, store_sleep_max_freq);
|
||||
|
||||
static ssize_t show_sample_rate_jiffies(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", sample_rate_jiffies);
|
||||
}
|
||||
|
||||
static ssize_t store_sample_rate_jiffies(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input > 0 && input <= 1000)
|
||||
sample_rate_jiffies = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr sample_rate_jiffies_attr = __ATTR(sample_rate_jiffies, 0644,
|
||||
show_sample_rate_jiffies, store_sample_rate_jiffies);
|
||||
|
||||
static ssize_t show_max_ramp_up(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", max_ramp_up);
|
||||
}
|
||||
|
||||
static ssize_t store_max_ramp_up(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input > 10000)
|
||||
max_ramp_up = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr max_ramp_up_attr = __ATTR(max_ramp_up, 0644,
|
||||
show_max_ramp_up, store_max_ramp_up);
|
||||
|
||||
static ssize_t show_max_cpu_load(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", max_cpu_load);
|
||||
}
|
||||
|
||||
static ssize_t store_max_cpu_load(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input > 0 && input <= 100)
|
||||
max_cpu_load = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr max_cpu_load_attr = __ATTR(max_cpu_load, 0644,
|
||||
show_max_cpu_load, store_max_cpu_load);
|
||||
|
||||
static ssize_t show_min_cpu_load(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%lu\n", min_cpu_load);
|
||||
}
|
||||
|
||||
static ssize_t store_min_cpu_load(struct cpufreq_policy *policy, const char *buf, size_t count)
|
||||
{
|
||||
ssize_t res;
|
||||
unsigned long input;
|
||||
res = strict_strtoul(buf, 0, &input);
|
||||
if (res >= 0 && input > 0 && input < 100)
|
||||
min_cpu_load = input;
|
||||
return res;
|
||||
}
|
||||
|
||||
static struct freq_attr min_cpu_load_attr = __ATTR(min_cpu_load, 0644,
|
||||
show_min_cpu_load, store_min_cpu_load);
|
||||
|
||||
static struct attribute * smartass_attributes[] = {
|
||||
&ramp_down_rate_ns_attr.attr,
|
||||
&up_min_freq_attr.attr,
|
||||
&sleep_max_freq_attr.attr,
|
||||
&sample_rate_jiffies_attr.attr,
|
||||
&max_ramp_up_attr.attr,
|
||||
&max_cpu_load_attr.attr,
|
||||
&min_cpu_load_attr.attr,
|
||||
NULL,
|
||||
};
|
||||
|
||||
static struct attribute_group smartass_attr_group = {
|
||||
.attrs = smartass_attributes,
|
||||
.name = "smartass",
|
||||
};
|
||||
|
||||
static int cpufreq_governor_smartass(struct cpufreq_policy *new_policy,
|
||||
unsigned int event)
|
||||
{
|
||||
unsigned int cpu = new_policy->cpu;
|
||||
int rc;
|
||||
struct smartass_info_s *this_smartass = &per_cpu(smartass_info, cpu);
|
||||
|
||||
switch (event) {
|
||||
case CPUFREQ_GOV_START:
|
||||
if ((!cpu_online(cpu)) || (!new_policy->cur))
|
||||
return -EINVAL;
|
||||
|
||||
if (this_smartass->enable) /* Already enabled */
|
||||
break;
|
||||
|
||||
/*
|
||||
* 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(&new_policy->kobj, &smartass_attr_group);
|
||||
if (rc)
|
||||
return rc;
|
||||
pm_idle_old = pm_idle;
|
||||
pm_idle = cpufreq_idle;
|
||||
|
||||
this_smartass->cur_policy = new_policy;
|
||||
this_smartass->enable = 1;
|
||||
|
||||
// notice no break here!
|
||||
|
||||
case CPUFREQ_GOV_LIMITS:
|
||||
if (this_smartass->cur_policy->cur != new_policy->max)
|
||||
__cpufreq_driver_target(new_policy, new_policy->max, CPUFREQ_RELATION_H);
|
||||
|
||||
break;
|
||||
|
||||
case CPUFREQ_GOV_STOP:
|
||||
this_smartass->enable = 0;
|
||||
|
||||
if (atomic_dec_return(&active_count) > 1)
|
||||
return 0;
|
||||
sysfs_remove_group(&new_policy->kobj,
|
||||
&smartass_attr_group);
|
||||
|
||||
pm_idle = pm_idle_old;
|
||||
del_timer(&this_smartass->timer);
|
||||
break;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static void smartass_suspend(int cpu, int suspend)
|
||||
{
|
||||
struct smartass_info_s *this_smartass = &per_cpu(smartass_info, smp_processor_id());
|
||||
struct cpufreq_policy *policy = this_smartass->cur_policy;
|
||||
unsigned int new_freq;
|
||||
|
||||
if (!this_smartass->enable || sleep_max_freq==0) // disable behavior for sleep_max_freq==0
|
||||
return;
|
||||
|
||||
if (suspend) {
|
||||
if (policy->cur > sleep_max_freq) {
|
||||
new_freq = sleep_max_freq;
|
||||
if (new_freq > policy->max)
|
||||
new_freq = policy->max;
|
||||
if (new_freq < policy->min)
|
||||
new_freq = policy->min;
|
||||
__cpufreq_driver_target(policy, new_freq,
|
||||
CPUFREQ_RELATION_H);
|
||||
}
|
||||
} else { // resume at max speed:
|
||||
__cpufreq_driver_target(policy, policy->max,
|
||||
CPUFREQ_RELATION_H);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
static void smartass_early_suspend(struct early_suspend *handler) {
|
||||
int i;
|
||||
suspended = 1;
|
||||
for_each_online_cpu(i)
|
||||
smartass_suspend(i,1);
|
||||
}
|
||||
|
||||
static void smartass_late_resume(struct early_suspend *handler) {
|
||||
int i;
|
||||
suspended = 0;
|
||||
for_each_online_cpu(i)
|
||||
smartass_suspend(i,0);
|
||||
}
|
||||
|
||||
static struct early_suspend smartass_power_suspend = {
|
||||
.suspend = smartass_early_suspend,
|
||||
.resume = smartass_late_resume,
|
||||
};
|
||||
|
||||
static int __init cpufreq_smartass_init(void)
|
||||
{
|
||||
unsigned int i;
|
||||
struct smartass_info_s *this_smartass;
|
||||
ramp_down_rate_ns = DEFAULT_RAMP_DOWN_RATE_NS;
|
||||
up_min_freq = DEFAULT_UP_MIN_FREQ;
|
||||
sleep_max_freq = DEFAULT_SLEEP_MAX_FREQ;
|
||||
sample_rate_jiffies = DEFAULT_SAMPLE_RATE_JIFFIES;
|
||||
max_ramp_up = DEFAULT_MAX_RAMP_UP;
|
||||
max_cpu_load = DEFAULT_MAX_CPU_LOAD;
|
||||
min_cpu_load = DEFAULT_MIN_CPU_LOAD;
|
||||
|
||||
suspended = 0;
|
||||
|
||||
/* Initalize per-cpu data: */
|
||||
for_each_possible_cpu(i) {
|
||||
this_smartass = &per_cpu(smartass_info, i);
|
||||
this_smartass->enable = 0;
|
||||
this_smartass->force_ramp_up = 0;
|
||||
this_smartass->time_in_idle = 0;
|
||||
this_smartass->idle_exit_time = 0;
|
||||
// intialize timer:
|
||||
init_timer_deferrable(&this_smartass->timer);
|
||||
this_smartass->timer.function = cpufreq_smartass_timer;
|
||||
this_smartass->timer.data = i;
|
||||
}
|
||||
|
||||
/* Scale up is high priority */
|
||||
up_wq = create_rt_workqueue("ksmartass_up");
|
||||
down_wq = create_workqueue("ksmartass_down");
|
||||
|
||||
INIT_WORK(&freq_scale_work, cpufreq_smartass_freq_change_time_work);
|
||||
|
||||
register_early_suspend(&smartass_power_suspend);
|
||||
|
||||
return cpufreq_register_governor(&cpufreq_gov_smartass);
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS
|
||||
pure_initcall(cpufreq_smartass_init);
|
||||
#else
|
||||
module_init(cpufreq_smartass_init);
|
||||
#endif
|
||||
|
||||
static void __exit cpufreq_smartass_exit(void)
|
||||
{
|
||||
cpufreq_unregister_governor(&cpufreq_gov_smartass);
|
||||
destroy_workqueue(up_wq);
|
||||
destroy_workqueue(down_wq);
|
||||
}
|
||||
|
||||
module_exit(cpufreq_smartass_exit);
|
||||
|
||||
MODULE_AUTHOR ("Erasmux");
|
||||
MODULE_DESCRIPTION ("'cpufreq_minmax' - A smart cpufreq governor optimized for the hero!");
|
||||
MODULE_LICENSE ("GPL");
|
@ -338,6 +338,9 @@ extern struct cpufreq_governor cpufreq_gov_ondemand;
|
||||
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_CONSERVATIVE)
|
||||
extern struct cpufreq_governor cpufreq_gov_conservative;
|
||||
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_conservative)
|
||||
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_SMARTASS)
|
||||
extern struct cpufreq_governor cpufreq_gov_smartass;
|
||||
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_smartass)
|
||||
#elif defined(CONFIG_CPU_FREQ_DEFAULT_GOV_INTERACTIVE)
|
||||
extern struct cpufreq_governor cpufreq_gov_interactive;
|
||||
#define CPUFREQ_DEFAULT_GOVERNOR (&cpufreq_gov_interactive)
|
||||
|
Loading…
x
Reference in New Issue
Block a user