Created
October 17, 2017 08:29
-
-
Save SDSkyKlouD/9b1e65f42b595e9ec02cdd7165a8564c to your computer and use it in GitHub Desktop.
CPUFreq 'alucard' governor (compilable in Xperia 4.4 kernel)
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
/* | |
* drivers/cpufreq/cpufreq_alucard.c | |
* | |
* Copyright (C) 2011 Samsung Electronics co. ltd | |
* ByungChang Cha <[email protected]> | |
* | |
* Based on ondemand governor | |
* Copyright (C) 2001 Russell King | |
* (C) 2003 Venkatesh Pallipadi <[email protected]>. | |
* Jun Nakajima <[email protected]> | |
* | |
* This program is free software; you can redistribute it and/or modify | |
* it under the terms of the GNU General Public License version 2 as | |
* published by the Free Software Foundation. | |
* | |
* Created by Alucard_24@xda | |
*/ | |
#include <linux/kernel.h> | |
#include <linux/module.h> | |
#include <linux/init.h> | |
#include <linux/cpufreq.h> | |
#include <linux/cpu.h> | |
#include <linux/jiffies.h> | |
#include <linux/kernel_stat.h> | |
#include <linux/mutex.h> | |
#include <linux/hrtimer.h> | |
#include <linux/tick.h> | |
#include <linux/ktime.h> | |
#include <linux/sched.h> | |
#include <linux/slab.h> | |
/* | |
* dbs is used in this file as a shortform for demandbased switching | |
* It helps to keep variable names smaller, simpler | |
*/ | |
/* Tuning Interface */ | |
#define MIN_SAMPLING_RATE 10000 | |
#define SAMPLING_RATE 100000 | |
#define INC_CPU_LOAD_AT_MIN_FREQ 90 | |
#define INC_CPU_LOAD 90 | |
#define DEC_CPU_LOAD_AT_MIN_FREQ 90 | |
#define DEC_CPU_LOAD 90 | |
#define CPUS_UP_RATE 1 | |
#define CPUS_DOWN_RATE 2 | |
#ifdef CONFIG_MACH_LGE | |
#define FREQ_RESPONSIVENESS 1574400 | |
#else | |
#define FREQ_RESPONSIVENESS 1134000 | |
#endif | |
/* Pump Inc/Dec for all cores */ | |
#define PUMP_INC_STEP_AT_MIN_FREQ 6 | |
#define PUMP_INC_STEP 1 | |
#define PUMP_DEC_STEP 1 | |
static void do_alucard_timer(struct work_struct *work); | |
struct cpufreq_alucard_cpuinfo { | |
u64 prev_cpu_wall; | |
u64 prev_cpu_idle; | |
struct cpufreq_frequency_table *freq_table; | |
struct delayed_work work; | |
struct cpufreq_policy *cur_policy; | |
int cpu; | |
int min_index; | |
int max_index; | |
int pump_inc_step; | |
int pump_inc_step_at_min_freq; | |
int pump_dec_step; | |
unsigned int cur_freq; | |
bool governor_enabled; | |
unsigned int up_rate; | |
unsigned int down_rate; | |
/* | |
* mutex that serializes governor limit change with | |
* do_alucard_timer invocation. We do not want do_alucard_timer to run | |
* when user is changing the governor or limits. | |
*/ | |
struct mutex timer_mutex; | |
}; | |
static DEFINE_PER_CPU(struct cpufreq_alucard_cpuinfo, od_alucard_cpuinfo); | |
static unsigned int alucard_enable; /* number of CPUs using this policy */ | |
/* | |
* alucard_mutex protects alucard_enable in governor start/stop. | |
*/ | |
static DEFINE_MUTEX(alucard_mutex); | |
/* alucard tuners */ | |
static struct alucard_tuners { | |
unsigned int sampling_rate; | |
int inc_cpu_load_at_min_freq; | |
int inc_cpu_load; | |
int dec_cpu_load_at_min_freq; | |
int dec_cpu_load; | |
int freq_responsiveness; | |
unsigned int io_is_busy; | |
unsigned int cpus_up_rate; | |
unsigned int cpus_down_rate; | |
} alucard_tuners_ins = { | |
.sampling_rate = SAMPLING_RATE, | |
.inc_cpu_load_at_min_freq = INC_CPU_LOAD_AT_MIN_FREQ, | |
.inc_cpu_load = INC_CPU_LOAD, | |
.dec_cpu_load_at_min_freq = DEC_CPU_LOAD_AT_MIN_FREQ, | |
.dec_cpu_load = DEC_CPU_LOAD, | |
.freq_responsiveness = FREQ_RESPONSIVENESS, | |
.io_is_busy = 0, | |
.cpus_up_rate = CPUS_UP_RATE, | |
.cpus_down_rate = CPUS_DOWN_RATE, | |
}; | |
/************************** sysfs interface ************************/ | |
/* cpufreq_alucard Governor Tunables */ | |
#define show_one(file_name, object) \ | |
static ssize_t show_##file_name \ | |
(struct kobject *kobj, struct attribute *attr, char *buf) \ | |
{ \ | |
return sprintf(buf, "%d\n", alucard_tuners_ins.object); \ | |
} | |
show_one(sampling_rate, sampling_rate); | |
show_one(inc_cpu_load_at_min_freq, inc_cpu_load_at_min_freq); | |
show_one(inc_cpu_load, inc_cpu_load); | |
show_one(dec_cpu_load_at_min_freq, dec_cpu_load_at_min_freq); | |
show_one(dec_cpu_load, dec_cpu_load); | |
show_one(freq_responsiveness, freq_responsiveness); | |
show_one(io_is_busy, io_is_busy); | |
show_one(cpus_up_rate, cpus_up_rate); | |
show_one(cpus_down_rate, cpus_down_rate); | |
#define show_pcpu_param(file_name, num_core) \ | |
static ssize_t show_##file_name##_##num_core \ | |
(struct kobject *kobj, struct attribute *attr, char *buf) \ | |
{ \ | |
struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, num_core - 1); \ | |
return sprintf(buf, "%d\n", \ | |
this_alucard_cpuinfo->file_name); \ | |
} | |
show_pcpu_param(pump_inc_step_at_min_freq, 1); | |
show_pcpu_param(pump_inc_step_at_min_freq, 2); | |
show_pcpu_param(pump_inc_step_at_min_freq, 3); | |
show_pcpu_param(pump_inc_step_at_min_freq, 4); | |
show_pcpu_param(pump_inc_step, 1); | |
show_pcpu_param(pump_inc_step, 2); | |
show_pcpu_param(pump_inc_step, 3); | |
show_pcpu_param(pump_inc_step, 4); | |
show_pcpu_param(pump_dec_step, 1); | |
show_pcpu_param(pump_dec_step, 2); | |
show_pcpu_param(pump_dec_step, 3); | |
show_pcpu_param(pump_dec_step, 4); | |
#define store_pcpu_param(file_name, num_core) \ | |
static ssize_t store_##file_name##_##num_core \ | |
(struct kobject *kobj, struct attribute *attr, \ | |
const char *buf, size_t count) \ | |
{ \ | |
int input; \ | |
struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo; \ | |
int ret; \ | |
\ | |
ret = sscanf(buf, "%d", &input); \ | |
if (ret != 1) \ | |
return -EINVAL; \ | |
\ | |
this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, num_core - 1); \ | |
\ | |
if (input == this_alucard_cpuinfo->file_name) { \ | |
return count; \ | |
} \ | |
\ | |
this_alucard_cpuinfo->file_name = input; \ | |
return count; \ | |
} | |
#define store_pcpu_pump_param(file_name, num_core) \ | |
static ssize_t store_##file_name##_##num_core \ | |
(struct kobject *kobj, struct attribute *attr, \ | |
const char *buf, size_t count) \ | |
{ \ | |
int input; \ | |
struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo; \ | |
int ret; \ | |
\ | |
ret = sscanf(buf, "%d", &input); \ | |
if (ret != 1) \ | |
return -EINVAL; \ | |
\ | |
input = min(max(1, input), 6); \ | |
\ | |
this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, num_core - 1); \ | |
\ | |
if (input == this_alucard_cpuinfo->file_name) { \ | |
return count; \ | |
} \ | |
\ | |
this_alucard_cpuinfo->file_name = input; \ | |
return count; \ | |
} | |
store_pcpu_pump_param(pump_inc_step_at_min_freq, 1); | |
store_pcpu_pump_param(pump_inc_step_at_min_freq, 2); | |
store_pcpu_pump_param(pump_inc_step_at_min_freq, 3); | |
store_pcpu_pump_param(pump_inc_step_at_min_freq, 4); | |
store_pcpu_pump_param(pump_inc_step, 1); | |
store_pcpu_pump_param(pump_inc_step, 2); | |
store_pcpu_pump_param(pump_inc_step, 3); | |
store_pcpu_pump_param(pump_inc_step, 4); | |
store_pcpu_pump_param(pump_dec_step, 1); | |
store_pcpu_pump_param(pump_dec_step, 2); | |
store_pcpu_pump_param(pump_dec_step, 3); | |
store_pcpu_pump_param(pump_dec_step, 4); | |
define_one_global_rw(pump_inc_step_at_min_freq_1); | |
define_one_global_rw(pump_inc_step_at_min_freq_2); | |
define_one_global_rw(pump_inc_step_at_min_freq_3); | |
define_one_global_rw(pump_inc_step_at_min_freq_4); | |
define_one_global_rw(pump_inc_step_1); | |
define_one_global_rw(pump_inc_step_2); | |
define_one_global_rw(pump_inc_step_3); | |
define_one_global_rw(pump_inc_step_4); | |
define_one_global_rw(pump_dec_step_1); | |
define_one_global_rw(pump_dec_step_2); | |
define_one_global_rw(pump_dec_step_3); | |
define_one_global_rw(pump_dec_step_4); | |
/* sampling_rate */ | |
static ssize_t store_sampling_rate(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%u", &input); | |
if (ret != 1) | |
return -EINVAL; | |
input = max(input,10000); | |
if (input == alucard_tuners_ins.sampling_rate) | |
return count; | |
alucard_tuners_ins.sampling_rate = input; | |
return count; | |
} | |
/* inc_cpu_load_at_min_freq */ | |
static ssize_t store_inc_cpu_load_at_min_freq(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%d", &input); | |
if (ret != 1) { | |
return -EINVAL; | |
} | |
input = min(input,alucard_tuners_ins.inc_cpu_load); | |
if (input == alucard_tuners_ins.inc_cpu_load_at_min_freq) | |
return count; | |
alucard_tuners_ins.inc_cpu_load_at_min_freq = input; | |
return count; | |
} | |
/* inc_cpu_load */ | |
static ssize_t store_inc_cpu_load(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%d", &input); | |
if (ret != 1) | |
return -EINVAL; | |
input = max(min(input,100),0); | |
if (input == alucard_tuners_ins.inc_cpu_load) | |
return count; | |
alucard_tuners_ins.inc_cpu_load = input; | |
return count; | |
} | |
/* dec_cpu_load_at_min_freq */ | |
static ssize_t store_dec_cpu_load_at_min_freq(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%d", &input); | |
if (ret != 1) { | |
return -EINVAL; | |
} | |
input = min(input,alucard_tuners_ins.dec_cpu_load); | |
if (input == alucard_tuners_ins.dec_cpu_load_at_min_freq) | |
return count; | |
alucard_tuners_ins.dec_cpu_load_at_min_freq = input; | |
return count; | |
} | |
/* dec_cpu_load */ | |
static ssize_t store_dec_cpu_load(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%d", &input); | |
if (ret != 1) | |
return -EINVAL; | |
input = max(min(input,95),5); | |
if (input == alucard_tuners_ins.dec_cpu_load) | |
return count; | |
alucard_tuners_ins.dec_cpu_load = input; | |
return count; | |
} | |
/* freq_responsiveness */ | |
static ssize_t store_freq_responsiveness(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
int input; | |
int ret; | |
ret = sscanf(buf, "%d", &input); | |
if (ret != 1) | |
return -EINVAL; | |
if (input == alucard_tuners_ins.freq_responsiveness) | |
return count; | |
alucard_tuners_ins.freq_responsiveness = input; | |
return count; | |
} | |
/* io_is_busy */ | |
static ssize_t store_io_is_busy(struct kobject *a, struct attribute *b, | |
const char *buf, size_t count) | |
{ | |
unsigned int input, j; | |
int ret; | |
ret = sscanf(buf, "%u", &input); | |
if (ret != 1) | |
return -EINVAL; | |
if (input > 1) | |
input = 1; | |
if (input == alucard_tuners_ins.io_is_busy) | |
return count; | |
alucard_tuners_ins.io_is_busy = !!input; | |
/* we need to re-evaluate prev_cpu_idle */ | |
for_each_online_cpu(j) { | |
struct cpufreq_alucard_cpuinfo *j_alucard_cpuinfo; | |
j_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, j); | |
j_alucard_cpuinfo->prev_cpu_idle = get_cpu_idle_time(j, | |
&j_alucard_cpuinfo->prev_cpu_wall, alucard_tuners_ins.io_is_busy); | |
} | |
return count; | |
} | |
/* cpus_up_rate */ | |
static ssize_t store_cpus_up_rate(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 == alucard_tuners_ins.cpus_up_rate) | |
return count; | |
alucard_tuners_ins.cpus_up_rate = input; | |
return count; | |
} | |
/* cpus_down_rate */ | |
static ssize_t store_cpus_down_rate(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 == alucard_tuners_ins.cpus_down_rate) | |
return count; | |
alucard_tuners_ins.cpus_down_rate = input; | |
return count; | |
} | |
define_one_global_rw(sampling_rate); | |
define_one_global_rw(inc_cpu_load_at_min_freq); | |
define_one_global_rw(inc_cpu_load); | |
define_one_global_rw(dec_cpu_load_at_min_freq); | |
define_one_global_rw(dec_cpu_load); | |
define_one_global_rw(freq_responsiveness); | |
define_one_global_rw(io_is_busy); | |
define_one_global_rw(cpus_up_rate); | |
define_one_global_rw(cpus_down_rate); | |
static struct attribute *alucard_attributes[] = { | |
&sampling_rate.attr, | |
&inc_cpu_load_at_min_freq.attr, | |
&inc_cpu_load.attr, | |
&dec_cpu_load_at_min_freq.attr, | |
&dec_cpu_load.attr, | |
&freq_responsiveness.attr, | |
&io_is_busy.attr, | |
&pump_inc_step_at_min_freq_1.attr, | |
&pump_inc_step_at_min_freq_2.attr, | |
&pump_inc_step_at_min_freq_3.attr, | |
&pump_inc_step_at_min_freq_4.attr, | |
&pump_inc_step_1.attr, | |
&pump_inc_step_2.attr, | |
&pump_inc_step_3.attr, | |
&pump_inc_step_4.attr, | |
&pump_dec_step_1.attr, | |
&pump_dec_step_2.attr, | |
&pump_dec_step_3.attr, | |
&pump_dec_step_4.attr, | |
&cpus_up_rate.attr, | |
&cpus_down_rate.attr, | |
NULL | |
}; | |
static struct attribute_group alucard_attr_group = { | |
.attrs = alucard_attributes, | |
.name = "alucard", | |
}; | |
/************************** sysfs end ************************/ | |
static void alucard_check_cpu(struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo) | |
{ | |
struct cpufreq_policy *cpu_policy; | |
unsigned int freq_responsiveness = alucard_tuners_ins.freq_responsiveness; | |
int dec_cpu_load = alucard_tuners_ins.dec_cpu_load; | |
int inc_cpu_load = alucard_tuners_ins.inc_cpu_load; | |
int pump_inc_step = this_alucard_cpuinfo->pump_inc_step; | |
int pump_dec_step = this_alucard_cpuinfo->pump_dec_step; | |
u64 cur_wall_time, cur_idle_time; | |
unsigned int wall_time, idle_time; | |
unsigned int index = 0; | |
unsigned int hi_index = 0; | |
int cur_load = -1; | |
unsigned int cpu; | |
int io_busy = alucard_tuners_ins.io_is_busy; | |
unsigned int cpus_up_rate = alucard_tuners_ins.cpus_up_rate; | |
unsigned int cpus_down_rate = alucard_tuners_ins.cpus_down_rate; | |
bool check_up = false, check_down = false; | |
cpu = this_alucard_cpuinfo->cpu; | |
cpu_policy = this_alucard_cpuinfo->cur_policy; | |
if (cpu_policy == NULL) | |
return; | |
cur_idle_time = get_cpu_idle_time(cpu, &cur_wall_time, io_busy); | |
wall_time = (unsigned int) | |
(cur_wall_time - this_alucard_cpuinfo->prev_cpu_wall); | |
this_alucard_cpuinfo->prev_cpu_wall = cur_wall_time; | |
idle_time = (unsigned int) | |
(cur_idle_time - this_alucard_cpuinfo->prev_cpu_idle); | |
this_alucard_cpuinfo->prev_cpu_idle = cur_idle_time; | |
/*printk(KERN_ERR "TIMER CPU[%u], wall[%u], idle[%u]\n",cpu, wall_time, idle_time);*/ | |
if (wall_time >= idle_time) { /*if wall_time < idle_time, evaluate cpu load next time*/ | |
cur_load = wall_time > idle_time ? (100 * (wall_time - idle_time)) / wall_time : 1;/*if wall_time is equal to idle_time cpu_load is equal to 1*/ | |
// cpufreq_notify_utilization(cpu_policy, cur_load); | |
if (this_alucard_cpuinfo->up_rate > cpus_up_rate) | |
this_alucard_cpuinfo->up_rate = 1; | |
if (this_alucard_cpuinfo->down_rate > cpus_down_rate) | |
this_alucard_cpuinfo->down_rate = 1; | |
/* Maximum increasing frequency possible */ | |
cpufreq_frequency_table_target(cpu_policy, this_alucard_cpuinfo->freq_table, max(cur_load * (cpu_policy->max / 100), cpu_policy->min), | |
CPUFREQ_RELATION_L, &hi_index); | |
cpufreq_frequency_table_target(cpu_policy, this_alucard_cpuinfo->freq_table, cpu_policy->cur, | |
CPUFREQ_RELATION_C, &index); | |
check_up = (this_alucard_cpuinfo->up_rate % cpus_up_rate == 0); | |
check_down = (this_alucard_cpuinfo->down_rate % cpus_down_rate == 0); | |
/* CPUs Online Scale Frequency*/ | |
if (cpu_policy->cur < freq_responsiveness) { | |
inc_cpu_load = alucard_tuners_ins.inc_cpu_load_at_min_freq; | |
dec_cpu_load = alucard_tuners_ins.dec_cpu_load_at_min_freq; | |
pump_inc_step = this_alucard_cpuinfo->pump_inc_step_at_min_freq; | |
hi_index = this_alucard_cpuinfo->max_index; | |
check_up = true; | |
check_down = true; | |
} | |
/* Check for frequency increase or for frequency decrease */ | |
if (cur_load >= inc_cpu_load && index < hi_index) { | |
++this_alucard_cpuinfo->up_rate; | |
if (check_up) { | |
if ((index + pump_inc_step) >= hi_index) | |
index = hi_index; | |
else | |
index += pump_inc_step; | |
this_alucard_cpuinfo->up_rate = 1; | |
this_alucard_cpuinfo->down_rate = 1; | |
} | |
} else if (cur_load < dec_cpu_load && index > this_alucard_cpuinfo->min_index) { | |
++this_alucard_cpuinfo->down_rate; | |
if (check_down) { | |
if ((index - pump_dec_step) <= this_alucard_cpuinfo->min_index) | |
index = this_alucard_cpuinfo->min_index; | |
else | |
index -= pump_dec_step; | |
this_alucard_cpuinfo->up_rate = 1; | |
this_alucard_cpuinfo->down_rate = 1; | |
} | |
} | |
this_alucard_cpuinfo->cur_freq = this_alucard_cpuinfo->freq_table[index].frequency; | |
/*printk(KERN_ERR "FREQ CALC.: CPU[%u], load[%d], target freq[%u], cur freq[%u], min freq[%u], max_freq[%u]\n",cpu, cur_load, this_alucard_cpuinfo->freq_table[index].frequency, cpu_policy->cur, cpu_policy->min, this_alucard_cpuinfo->freq_table[hi_index].frequency);*/ | |
if (this_alucard_cpuinfo->cur_freq != cpu_policy->cur) { | |
__cpufreq_driver_target(cpu_policy, this_alucard_cpuinfo->cur_freq, CPUFREQ_RELATION_C); | |
} | |
} | |
} | |
static void do_alucard_timer(struct work_struct *work) | |
{ | |
struct cpufreq_alucard_cpuinfo *alucard_cpuinfo; | |
int delay; | |
unsigned int cpu; | |
alucard_cpuinfo = container_of(work, struct cpufreq_alucard_cpuinfo, work.work); | |
cpu = alucard_cpuinfo->cpu; | |
mutex_lock(&alucard_cpuinfo->timer_mutex); | |
alucard_check_cpu(alucard_cpuinfo); | |
delay = usecs_to_jiffies(alucard_tuners_ins.sampling_rate); | |
/* We want all CPUs to do sampling nearly on same jiffy */ | |
if (num_online_cpus() > 1) | |
delay -= jiffies % delay; | |
if (delay > 0) | |
mod_delayed_work_on(cpu, system_wq, &alucard_cpuinfo->work, delay); | |
else | |
mod_delayed_work_on(cpu, system_wq, &alucard_cpuinfo->work, usecs_to_jiffies(MIN_SAMPLING_RATE)); | |
mutex_unlock(&alucard_cpuinfo->timer_mutex); | |
} | |
static int cpufreq_governor_alucard(struct cpufreq_policy *policy, | |
unsigned int event) | |
{ | |
unsigned int cpu; | |
struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo; | |
int rc, delay; | |
int io_busy; | |
cpu = policy->cpu; | |
io_busy = alucard_tuners_ins.io_is_busy; | |
this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, cpu); | |
this_alucard_cpuinfo->freq_table = cpufreq_frequency_get_table(cpu); | |
switch (event) { | |
case CPUFREQ_GOV_START: | |
if ((!cpu_online(cpu)) || (!policy->cur)) | |
return -EINVAL; | |
mutex_lock(&alucard_mutex); | |
this_alucard_cpuinfo->cpu = cpu; | |
this_alucard_cpuinfo->cur_policy = policy; | |
this_alucard_cpuinfo->prev_cpu_idle = get_cpu_idle_time(cpu, &this_alucard_cpuinfo->prev_cpu_wall, io_busy); | |
cpufreq_frequency_table_target(policy, this_alucard_cpuinfo->freq_table, policy->min, | |
CPUFREQ_RELATION_L, &this_alucard_cpuinfo->min_index); | |
cpufreq_frequency_table_target(policy, this_alucard_cpuinfo->freq_table, policy->max, | |
CPUFREQ_RELATION_H, &this_alucard_cpuinfo->max_index); | |
this_alucard_cpuinfo->cur_freq = policy->cur; | |
alucard_enable++; | |
/* | |
* Start the timerschedule work, when this governor | |
* is used for first time | |
*/ | |
if (alucard_enable == 1) { | |
rc = sysfs_create_group(cpufreq_global_kobject, | |
&alucard_attr_group); | |
if (rc) { | |
alucard_enable--; | |
mutex_unlock(&alucard_mutex); | |
return rc; | |
} | |
} | |
this_alucard_cpuinfo->up_rate = 1; | |
this_alucard_cpuinfo->down_rate = 1; | |
this_alucard_cpuinfo->governor_enabled = true; | |
mutex_unlock(&alucard_mutex); | |
mutex_init(&this_alucard_cpuinfo->timer_mutex); | |
delay = usecs_to_jiffies(alucard_tuners_ins.sampling_rate); | |
/* We want all CPUs to do sampling nearly on same jiffy */ | |
if (num_online_cpus() > 1) | |
delay -= jiffies % delay; | |
INIT_DEFERRABLE_WORK(&this_alucard_cpuinfo->work, do_alucard_timer); | |
queue_delayed_work_on(this_alucard_cpuinfo->cpu, system_wq, &this_alucard_cpuinfo->work, delay); | |
break; | |
case CPUFREQ_GOV_STOP: | |
cancel_delayed_work_sync(&this_alucard_cpuinfo->work); | |
mutex_lock(&alucard_mutex); | |
mutex_destroy(&this_alucard_cpuinfo->timer_mutex); | |
this_alucard_cpuinfo->governor_enabled = false; | |
this_alucard_cpuinfo->cur_policy = NULL; | |
alucard_enable--; | |
if (!alucard_enable) { | |
sysfs_remove_group(cpufreq_global_kobject, | |
&alucard_attr_group); | |
} | |
this_alucard_cpuinfo->cur_freq = 0; | |
mutex_unlock(&alucard_mutex); | |
break; | |
case CPUFREQ_GOV_LIMITS: | |
if (!this_alucard_cpuinfo->cur_policy) { | |
pr_debug("Unable to limit cpu freq due to cur_policy == NULL\n"); | |
return -EPERM; | |
} | |
mutex_lock(&this_alucard_cpuinfo->timer_mutex); | |
cpufreq_frequency_table_target(policy, this_alucard_cpuinfo->freq_table, policy->min, | |
CPUFREQ_RELATION_L, &this_alucard_cpuinfo->min_index); | |
cpufreq_frequency_table_target(policy, this_alucard_cpuinfo->freq_table, policy->max, | |
CPUFREQ_RELATION_H, &this_alucard_cpuinfo->max_index); | |
if (policy->max < this_alucard_cpuinfo->cur_policy->cur) | |
__cpufreq_driver_target(this_alucard_cpuinfo->cur_policy, | |
policy->max, CPUFREQ_RELATION_H); | |
else if (policy->min > this_alucard_cpuinfo->cur_policy->cur) | |
__cpufreq_driver_target(this_alucard_cpuinfo->cur_policy, | |
policy->min, CPUFREQ_RELATION_L); | |
this_alucard_cpuinfo->cur_freq = policy->cur; | |
mutex_unlock(&this_alucard_cpuinfo->timer_mutex); | |
break; | |
} | |
return 0; | |
} | |
#ifndef CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD | |
static | |
#endif | |
struct cpufreq_governor cpufreq_gov_alucard = { | |
.name = "alucard", | |
.governor = cpufreq_governor_alucard, | |
.owner = THIS_MODULE, | |
}; | |
static int __init cpufreq_gov_alucard_init(void) | |
{ | |
unsigned int cpu; | |
for_each_possible_cpu(cpu) { | |
struct cpufreq_alucard_cpuinfo *this_alucard_cpuinfo = &per_cpu(od_alucard_cpuinfo, cpu); | |
this_alucard_cpuinfo->pump_inc_step_at_min_freq = PUMP_INC_STEP_AT_MIN_FREQ; | |
this_alucard_cpuinfo->pump_inc_step = PUMP_INC_STEP; | |
this_alucard_cpuinfo->pump_dec_step = PUMP_DEC_STEP; | |
} | |
return cpufreq_register_governor(&cpufreq_gov_alucard); | |
} | |
static void __exit cpufreq_gov_alucard_exit(void) | |
{ | |
cpufreq_unregister_governor(&cpufreq_gov_alucard); | |
} | |
MODULE_AUTHOR("Alucard24@XDA"); | |
MODULE_DESCRIPTION("'cpufreq_alucard' - A dynamic cpufreq governor v1.1 (SnapDragon)"); | |
MODULE_LICENSE("GPL"); | |
#ifdef CONFIG_CPU_FREQ_DEFAULT_GOV_ALUCARD | |
fs_initcall(cpufreq_gov_alucard_init); | |
#else | |
module_init(cpufreq_gov_alucard_init); | |
#endif | |
module_exit(cpufreq_gov_alucard_exit); |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment