264 lines
6.0 KiB
C
264 lines
6.0 KiB
C
/*
|
|
* linux/drivers/cpufreq/proc_intf.c
|
|
*
|
|
* Copyright (C) 2002 - 2003 Dominik Brodowski
|
|
*/
|
|
|
|
#include <linux/kernel.h>
|
|
#include <linux/module.h>
|
|
#include <linux/init.h>
|
|
#include <linux/cpufreq.h>
|
|
#include <linux/ctype.h>
|
|
#include <linux/proc_fs.h>
|
|
#include <asm/uaccess.h>
|
|
|
|
#warning This module will be removed from the 2.6. kernel series soon after 2005-01-01
|
|
|
|
#define CPUFREQ_ALL_CPUS ((NR_CPUS))
|
|
|
|
static unsigned int warning_print = 0;
|
|
|
|
/**
|
|
* cpufreq_parse_policy - parse a policy string
|
|
* @input_string: the string to parse.
|
|
* @policy: the policy written inside input_string
|
|
*
|
|
* This function parses a "policy string" - something the user echo'es into
|
|
* /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
|
|
* If there are invalid/missing entries, they are replaced with current
|
|
* cpufreq policy.
|
|
*/
|
|
static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
|
|
{
|
|
unsigned int min = 0;
|
|
unsigned int max = 0;
|
|
unsigned int cpu = 0;
|
|
char str_governor[16];
|
|
struct cpufreq_policy current_policy;
|
|
unsigned int result = -EFAULT;
|
|
|
|
if (!policy)
|
|
return -EINVAL;
|
|
|
|
policy->min = 0;
|
|
policy->max = 0;
|
|
policy->policy = 0;
|
|
policy->cpu = CPUFREQ_ALL_CPUS;
|
|
|
|
if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4)
|
|
{
|
|
policy->min = min;
|
|
policy->max = max;
|
|
policy->cpu = cpu;
|
|
result = 0;
|
|
goto scan_policy;
|
|
}
|
|
if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4)
|
|
{
|
|
if (!cpufreq_get_policy(¤t_policy, cpu)) {
|
|
policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
|
|
policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
|
|
policy->cpu = cpu;
|
|
result = 0;
|
|
goto scan_policy;
|
|
}
|
|
}
|
|
|
|
if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3)
|
|
{
|
|
policy->min = min;
|
|
policy->max = max;
|
|
result = 0;
|
|
goto scan_policy;
|
|
}
|
|
|
|
if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3)
|
|
{
|
|
if (!cpufreq_get_policy(¤t_policy, cpu)) {
|
|
policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
|
|
policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
|
|
result = 0;
|
|
goto scan_policy;
|
|
}
|
|
}
|
|
|
|
return -EINVAL;
|
|
|
|
scan_policy:
|
|
result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
|
|
|
|
return result;
|
|
}
|
|
|
|
/**
|
|
* cpufreq_proc_read - read /proc/cpufreq
|
|
*
|
|
* This function prints out the current cpufreq policy.
|
|
*/
|
|
static int cpufreq_proc_read (
|
|
char *page,
|
|
char **start,
|
|
off_t off,
|
|
int count,
|
|
int *eof,
|
|
void *data)
|
|
{
|
|
char *p = page;
|
|
int len = 0;
|
|
struct cpufreq_policy policy;
|
|
unsigned int min_pctg = 0;
|
|
unsigned int max_pctg = 0;
|
|
unsigned int i = 0;
|
|
|
|
if (off != 0)
|
|
goto end;
|
|
|
|
if (!warning_print) {
|
|
warning_print++;
|
|
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
|
|
"will be removed from (new) 2.6. kernels soon "
|
|
"after 2005-01-01\n");
|
|
}
|
|
|
|
p += sprintf(p, " minimum CPU frequency - maximum CPU frequency - policy\n");
|
|
for (i=0;i<NR_CPUS;i++) {
|
|
if (!cpu_online(i))
|
|
continue;
|
|
|
|
if (cpufreq_get_policy(&policy, i))
|
|
continue;
|
|
|
|
if (!policy.cpuinfo.max_freq)
|
|
continue;
|
|
|
|
min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq;
|
|
max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq;
|
|
|
|
p += sprintf(p, "CPU%3d %9d kHz (%3d %%) - %9d kHz (%3d %%) - ",
|
|
i , policy.min, min_pctg, policy.max, max_pctg);
|
|
if (policy.policy) {
|
|
switch (policy.policy) {
|
|
case CPUFREQ_POLICY_POWERSAVE:
|
|
p += sprintf(p, "powersave\n");
|
|
break;
|
|
case CPUFREQ_POLICY_PERFORMANCE:
|
|
p += sprintf(p, "performance\n");
|
|
break;
|
|
default:
|
|
p += sprintf(p, "INVALID\n");
|
|
break;
|
|
}
|
|
} else
|
|
p += scnprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
|
|
}
|
|
end:
|
|
len = (p - page);
|
|
if (len <= off+count)
|
|
*eof = 1;
|
|
*start = page + off;
|
|
len -= off;
|
|
if (len>count)
|
|
len = count;
|
|
if (len<0)
|
|
len = 0;
|
|
|
|
return len;
|
|
}
|
|
|
|
|
|
/**
|
|
* cpufreq_proc_write - handles writing into /proc/cpufreq
|
|
*
|
|
* This function calls the parsing script and then sets the policy
|
|
* accordingly.
|
|
*/
|
|
static int cpufreq_proc_write (
|
|
struct file *file,
|
|
const char __user *buffer,
|
|
unsigned long count,
|
|
void *data)
|
|
{
|
|
int result = 0;
|
|
char proc_string[42] = {'\0'};
|
|
struct cpufreq_policy policy;
|
|
unsigned int i = 0;
|
|
|
|
|
|
if ((count > sizeof(proc_string) - 1))
|
|
return -EINVAL;
|
|
|
|
if (copy_from_user(proc_string, buffer, count))
|
|
return -EFAULT;
|
|
|
|
if (!warning_print) {
|
|
warning_print++;
|
|
printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
|
|
"will be removed from (new) 2.6. kernels soon "
|
|
"after 2005-01-01\n");
|
|
}
|
|
|
|
proc_string[count] = '\0';
|
|
|
|
result = cpufreq_parse_policy(proc_string, &policy);
|
|
if (result)
|
|
return -EFAULT;
|
|
|
|
if (policy.cpu == CPUFREQ_ALL_CPUS)
|
|
{
|
|
for (i=0; i<NR_CPUS; i++)
|
|
{
|
|
policy.cpu = i;
|
|
if (cpu_online(i))
|
|
cpufreq_set_policy(&policy);
|
|
}
|
|
}
|
|
else
|
|
cpufreq_set_policy(&policy);
|
|
|
|
return count;
|
|
}
|
|
|
|
|
|
/**
|
|
* cpufreq_proc_init - add "cpufreq" to the /proc root directory
|
|
*
|
|
* This function adds "cpufreq" to the /proc root directory.
|
|
*/
|
|
static int __init cpufreq_proc_init (void)
|
|
{
|
|
struct proc_dir_entry *entry = NULL;
|
|
|
|
/* are these acceptable values? */
|
|
entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR,
|
|
&proc_root);
|
|
|
|
if (!entry) {
|
|
printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
|
|
return -EIO;
|
|
} else {
|
|
entry->read_proc = cpufreq_proc_read;
|
|
entry->write_proc = cpufreq_proc_write;
|
|
}
|
|
|
|
return 0;
|
|
}
|
|
|
|
|
|
/**
|
|
* cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
|
|
*
|
|
* This function removes "cpufreq" from the /proc root directory.
|
|
*/
|
|
static void __exit cpufreq_proc_exit (void)
|
|
{
|
|
remove_proc_entry("cpufreq", &proc_root);
|
|
return;
|
|
}
|
|
|
|
MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
|
|
MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface");
|
|
MODULE_LICENSE ("GPL");
|
|
|
|
module_init(cpufreq_proc_init);
|
|
module_exit(cpufreq_proc_exit);
|