mirror of
https://github.com/followmsi/android_kernel_google_msm.git
synced 2024-11-06 23:17:41 +00:00
cpufreq: Create DVFS stress test function.
Change-Id: I98897314ff0df9f4fcf22c9d45b80a43268c8bba Reviewed-on: http://mcrd1-5.corpnet.asus/code-review/master/67932 Reviewed-by: Singhome Lee <singhome_lee@asus.com> Tested-by: Singhome Lee <singhome_lee@asus.com>
This commit is contained in:
parent
3a6924ba6e
commit
ca2d4e94af
3 changed files with 174 additions and 2 deletions
|
@ -604,6 +604,31 @@ static ssize_t show_scaling_setspeed(struct cpufreq_policy *policy, char *buf)
|
|||
return policy->governor->show_setspeed(policy, buf);
|
||||
}
|
||||
|
||||
static ssize_t store_dvfs_test(struct cpufreq_policy *policy,
|
||||
const char *buf, size_t count)
|
||||
{
|
||||
unsigned int enable= 0;
|
||||
unsigned int ret;
|
||||
|
||||
if (!policy->governor || !policy->governor->start_dvfs_test)
|
||||
return -EINVAL;
|
||||
|
||||
ret = sscanf(buf, "%u", &enable);
|
||||
if (ret != 1)
|
||||
return -EINVAL;
|
||||
|
||||
policy->governor->start_dvfs_test(policy, enable);
|
||||
|
||||
return count;
|
||||
}
|
||||
|
||||
static ssize_t show_dvfs_test(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
if (!policy->governor || !policy->governor->show_dvfs_test)
|
||||
return sprintf(buf, "<unsupported>\n");
|
||||
|
||||
return policy->governor->show_dvfs_test(policy, buf);
|
||||
}
|
||||
/**
|
||||
* show_scaling_driver - show the current cpufreq HW/BIOS limitation
|
||||
*/
|
||||
|
@ -634,6 +659,7 @@ cpufreq_freq_attr_rw(scaling_min_freq);
|
|||
cpufreq_freq_attr_rw(scaling_max_freq);
|
||||
cpufreq_freq_attr_rw(scaling_governor);
|
||||
cpufreq_freq_attr_rw(scaling_setspeed);
|
||||
cpufreq_freq_attr_rw(dvfs_test);
|
||||
|
||||
static struct attribute *default_attrs[] = {
|
||||
&cpuinfo_min_freq.attr,
|
||||
|
@ -648,6 +674,7 @@ static struct attribute *default_attrs[] = {
|
|||
&scaling_driver.attr,
|
||||
&scaling_available_governors.attr,
|
||||
&scaling_setspeed.attr,
|
||||
&dvfs_test.attr,
|
||||
NULL
|
||||
};
|
||||
|
||||
|
|
|
@ -23,6 +23,8 @@
|
|||
#include <linux/fs.h>
|
||||
#include <linux/sysfs.h>
|
||||
#include <linux/mutex.h>
|
||||
#include <linux/delay.h>
|
||||
#include <asm/uaccess.h>
|
||||
|
||||
/**
|
||||
* A few values needed by the userspace governor
|
||||
|
@ -33,7 +35,7 @@ static DEFINE_PER_CPU(unsigned int, cpu_cur_freq); /* current CPU freq */
|
|||
static DEFINE_PER_CPU(unsigned int, cpu_set_freq); /* CPU freq desired by
|
||||
userspace */
|
||||
static DEFINE_PER_CPU(unsigned int, cpu_is_managed);
|
||||
|
||||
static DEFINE_PER_CPU(struct cpufreq_policy *, temp_policy);
|
||||
static DEFINE_MUTEX(userspace_mutex);
|
||||
static int cpus_using_userspace_governor;
|
||||
|
||||
|
@ -59,8 +61,139 @@ userspace_cpufreq_notifier(struct notifier_block *nb, unsigned long val,
|
|||
static struct notifier_block userspace_cpufreq_notifier_block = {
|
||||
.notifier_call = userspace_cpufreq_notifier
|
||||
};
|
||||
//=========dvfs stress test ===================
|
||||
extern struct cpufreq_frequency_table * cpufreq_frequency_get_table(unsigned int cpu);
|
||||
struct cpufreq_frequency_table *cpu_freq_table=NULL;
|
||||
struct workqueue_struct *dvfs_test_work_queue=NULL;
|
||||
struct delayed_work stress_test;
|
||||
bool stress_test_enable=false;
|
||||
unsigned int max_cpu_freq_index=CPUFREQ_TABLE_END;
|
||||
int freq_index=0;
|
||||
static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq);
|
||||
static bool cpufreq_set_userspace_governor(void);
|
||||
void dvfs_stress_test(struct work_struct *work)
|
||||
{
|
||||
int cpu=0;
|
||||
static int start_testing=0;
|
||||
if(!start_testing){
|
||||
cpufreq_set_userspace_governor();
|
||||
start_testing=1;
|
||||
}
|
||||
cpu=0;
|
||||
|
||||
if(stress_test_enable)
|
||||
mutex_lock(&userspace_mutex);
|
||||
|
||||
for_each_online_cpu(cpu){
|
||||
if(per_cpu(temp_policy,cpu) && per_cpu(cpu_is_managed, cpu)){
|
||||
cpufreq_set(per_cpu(temp_policy,cpu), cpu_freq_table[freq_index].frequency);
|
||||
}
|
||||
}
|
||||
|
||||
if(stress_test_enable)
|
||||
mutex_unlock(&userspace_mutex);
|
||||
|
||||
freq_index--;
|
||||
if(freq_index<0)
|
||||
freq_index=max_cpu_freq_index;
|
||||
if(stress_test_enable)
|
||||
queue_delayed_work(dvfs_test_work_queue, &stress_test,1*HZ);
|
||||
return ;
|
||||
}
|
||||
|
||||
static bool cpufreq_set_userspace_governor(void)
|
||||
{
|
||||
static char *cpufreq_sysfs_governor_path="/sys/devices/system/cpu/cpu%i/cpufreq/scaling_governor";
|
||||
static char *cpufreq_sysfs_online_path="/sys/devices/system/cpu/cpu%i/online";
|
||||
struct file *scaling_gov = NULL;
|
||||
struct file *cpux_online= NULL;
|
||||
static char *governor = "userspace";
|
||||
static char cpu_on[1] = {'1'};
|
||||
mm_segment_t old_fs;
|
||||
char buf[128];
|
||||
int i;
|
||||
bool err=0;
|
||||
loff_t offset = 0;
|
||||
struct cpufreq_policy *policy =NULL;
|
||||
|
||||
printk("cpufreq_set_userspace_governor+\n");
|
||||
/* change to KERNEL_DS address limit */
|
||||
old_fs = get_fs();
|
||||
set_fs(KERNEL_DS);
|
||||
for(i = 1; i <= 3; i++) {
|
||||
sprintf(buf, cpufreq_sysfs_online_path, i);
|
||||
cpux_online = filp_open(buf, O_RDWR, 0);
|
||||
|
||||
if (IS_ERR_OR_NULL(cpux_online)){
|
||||
printk("cpufreq_set_userspace_governor: open %s fail\n", buf);
|
||||
err = true;
|
||||
goto error;
|
||||
}
|
||||
|
||||
cpux_online->f_op->write(cpux_online, cpu_on, strlen(cpu_on), &offset);
|
||||
|
||||
memset(buf,0,sizeof(buf));
|
||||
sprintf(buf, cpufreq_sysfs_governor_path, i);
|
||||
scaling_gov = filp_open(buf, O_RDWR, 0);
|
||||
if (IS_ERR_OR_NULL(scaling_gov)) {
|
||||
printk("cpufreq_set_userspace_governor: open %s fail\n", buf);
|
||||
err = true;
|
||||
goto error;
|
||||
}
|
||||
|
||||
policy =cpufreq_cpu_get(i);
|
||||
if(policy) {
|
||||
if(!strncmp(policy->governor->name, governor, 9)) {
|
||||
printk("cpufreq_set_userspace_governor cpu%u is userspace\n", i);
|
||||
if (policy)
|
||||
cpufreq_cpu_put(policy);
|
||||
continue;
|
||||
}
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
if (scaling_gov->f_op != NULL && scaling_gov->f_op->write != NULL) {
|
||||
scaling_gov->f_op->write(scaling_gov,
|
||||
governor,
|
||||
strlen(governor),
|
||||
&offset);
|
||||
} else
|
||||
pr_err("f_op might be null\n");
|
||||
|
||||
filp_close(scaling_gov, NULL);
|
||||
filp_close(cpux_online, NULL);
|
||||
}
|
||||
|
||||
printk("cpufreq_set_userspace_governor-\n");
|
||||
error:
|
||||
set_fs(old_fs);
|
||||
return err;
|
||||
}
|
||||
static int start_test(struct cpufreq_policy *policy, unsigned int enable)
|
||||
{
|
||||
int i=0;
|
||||
if(policy->cpu==0 && enable ){
|
||||
cpu_freq_table=cpufreq_frequency_get_table(0);
|
||||
|
||||
for (i = 0; (cpu_freq_table[i].frequency != CPUFREQ_TABLE_END); i++) {
|
||||
if (cpu_freq_table[i].frequency == CPUFREQ_ENTRY_INVALID)
|
||||
continue;
|
||||
printk("start_test cpu_freq_table[%u].frequency=%u\n",i,cpu_freq_table[i].frequency);
|
||||
}
|
||||
|
||||
freq_index=max_cpu_freq_index=i-1;
|
||||
stress_test_enable=true;
|
||||
queue_delayed_work(dvfs_test_work_queue, &stress_test,1*HZ);
|
||||
}else
|
||||
stress_test_enable=false;
|
||||
return true;
|
||||
}
|
||||
|
||||
static ssize_t show_test(struct cpufreq_policy *policy, char *buf)
|
||||
{
|
||||
return sprintf(buf, "%u\n", stress_test_enable);
|
||||
}
|
||||
//=========dvfs stress test ===================
|
||||
/**
|
||||
* cpufreq_set - set the CPU frequency
|
||||
* @policy: pointer to policy struct where freq is being set
|
||||
|
@ -72,8 +205,9 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
|
|||
{
|
||||
int ret = -EINVAL;
|
||||
|
||||
pr_debug("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
|
||||
printk("cpufreq_set for cpu %u, freq %u kHz\n", policy->cpu, freq);
|
||||
|
||||
if(!stress_test_enable)
|
||||
mutex_lock(&userspace_mutex);
|
||||
if (!per_cpu(cpu_is_managed, policy->cpu))
|
||||
goto err;
|
||||
|
@ -98,6 +232,7 @@ static int cpufreq_set(struct cpufreq_policy *policy, unsigned int freq)
|
|||
ret = __cpufreq_driver_target(policy, freq, CPUFREQ_RELATION_L);
|
||||
|
||||
err:
|
||||
if(!stress_test_enable)
|
||||
mutex_unlock(&userspace_mutex);
|
||||
return ret;
|
||||
}
|
||||
|
@ -118,6 +253,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
|
|||
case CPUFREQ_GOV_START:
|
||||
if (!cpu_online(cpu))
|
||||
return -EINVAL;
|
||||
per_cpu(temp_policy, cpu) =policy;
|
||||
BUG_ON(!policy->cur);
|
||||
mutex_lock(&userspace_mutex);
|
||||
|
||||
|
@ -155,6 +291,7 @@ static int cpufreq_governor_userspace(struct cpufreq_policy *policy,
|
|||
per_cpu(cpu_min_freq, cpu) = 0;
|
||||
per_cpu(cpu_max_freq, cpu) = 0;
|
||||
per_cpu(cpu_set_freq, cpu) = 0;
|
||||
per_cpu(temp_policy, cpu) =NULL;
|
||||
pr_debug("managing cpu %u stopped\n", cpu);
|
||||
mutex_unlock(&userspace_mutex);
|
||||
break;
|
||||
|
@ -194,11 +331,15 @@ struct cpufreq_governor cpufreq_gov_userspace = {
|
|||
.governor = cpufreq_governor_userspace,
|
||||
.store_setspeed = cpufreq_set,
|
||||
.show_setspeed = show_speed,
|
||||
.start_dvfs_test = start_test,
|
||||
.show_dvfs_test = show_test,
|
||||
.owner = THIS_MODULE,
|
||||
};
|
||||
|
||||
static int __init cpufreq_gov_userspace_init(void)
|
||||
{
|
||||
INIT_DELAYED_WORK(&stress_test, dvfs_stress_test) ;
|
||||
dvfs_test_work_queue = create_singlethread_workqueue("dvfs_test_workqueue");
|
||||
return cpufreq_register_governor(&cpufreq_gov_userspace);
|
||||
}
|
||||
|
||||
|
|
|
@ -181,6 +181,10 @@ struct cpufreq_governor {
|
|||
char *buf);
|
||||
int (*store_setspeed) (struct cpufreq_policy *policy,
|
||||
unsigned int freq);
|
||||
ssize_t (*show_dvfs_test) (struct cpufreq_policy *policy,
|
||||
char *buf);
|
||||
int (*start_dvfs_test) (struct cpufreq_policy *policy,
|
||||
unsigned int enable);
|
||||
unsigned int max_transition_latency; /* HW must be able to switch to
|
||||
next freq faster than this value in nano secs or we
|
||||
will fallback to performance governor */
|
||||
|
|
Loading…
Reference in a new issue