Skip to content

Instantly share code, notes, and snippets.

@SDSkyKlouD
Created October 17, 2017 08:29
Show Gist options
  • Save SDSkyKlouD/9b1e65f42b595e9ec02cdd7165a8564c to your computer and use it in GitHub Desktop.
Save SDSkyKlouD/9b1e65f42b595e9ec02cdd7165a8564c to your computer and use it in GitHub Desktop.
CPUFreq 'alucard' governor (compilable in Xperia 4.4 kernel)
/*
* 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