vserver 1.9.3
[linux-2.6.git] / drivers / cpufreq / proc_intf.c
1 /*
2  * linux/drivers/cpufreq/proc_intf.c
3  *
4  * Copyright (C) 2002 - 2003 Dominik Brodowski
5  */
6
7 #include <linux/kernel.h>
8 #include <linux/module.h>
9 #include <linux/init.h>
10 #include <linux/cpufreq.h>
11 #include <linux/ctype.h>
12 #include <linux/proc_fs.h>
13 #include <asm/uaccess.h>
14
15 #warning This module will be removed from the 2.6. kernel series soon after 2005-01-01
16
17 #define CPUFREQ_ALL_CPUS                ((NR_CPUS))
18
19 static unsigned int warning_print = 0;
20
21 /**
22  * cpufreq_parse_policy - parse a policy string
23  * @input_string: the string to parse.
24  * @policy: the policy written inside input_string
25  *
26  * This function parses a "policy string" - something the user echo'es into
27  * /proc/cpufreq or gives as boot parameter - into a struct cpufreq_policy.
28  * If there are invalid/missing entries, they are replaced with current
29  * cpufreq policy.
30  */
31 static int cpufreq_parse_policy(char input_string[42], struct cpufreq_policy *policy)
32 {
33         unsigned int            min = 0;
34         unsigned int            max = 0;
35         unsigned int            cpu = 0;
36         char                    str_governor[16];
37         struct cpufreq_policy   current_policy;
38         unsigned int            result = -EFAULT;
39
40         if (!policy)
41                 return -EINVAL;
42
43         policy->min = 0;
44         policy->max = 0;
45         policy->policy = 0;
46         policy->cpu = CPUFREQ_ALL_CPUS;
47
48         if (sscanf(input_string, "%d:%d:%d:%15s", &cpu, &min, &max, str_governor) == 4) 
49         {
50                 policy->min = min;
51                 policy->max = max;
52                 policy->cpu = cpu;
53                 result = 0;
54                 goto scan_policy;
55         }
56         if (sscanf(input_string, "%d%%%d%%%d%%%15s", &cpu, &min, &max, str_governor) == 4)
57         {
58                 if (!cpufreq_get_policy(&current_policy, cpu)) {
59                         policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
60                         policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
61                         policy->cpu = cpu;
62                         result = 0;
63                         goto scan_policy;
64                 }
65         }
66
67         if (sscanf(input_string, "%d:%d:%15s", &min, &max, str_governor) == 3) 
68         {
69                 policy->min = min;
70                 policy->max = max;
71                 result = 0;
72                 goto scan_policy;
73         }
74
75         if (sscanf(input_string, "%d%%%d%%%15s", &min, &max, str_governor) == 3)
76         {
77                 if (!cpufreq_get_policy(&current_policy, cpu)) {
78                         policy->min = (min * current_policy.cpuinfo.max_freq) / 100;
79                         policy->max = (max * current_policy.cpuinfo.max_freq) / 100;
80                         result = 0;
81                         goto scan_policy;
82                 }
83         }
84
85         return -EINVAL;
86
87 scan_policy:
88         result = cpufreq_parse_governor(str_governor, &policy->policy, &policy->governor);
89
90         return result;
91 }
92
93 /**
94  * cpufreq_proc_read - read /proc/cpufreq
95  *
96  * This function prints out the current cpufreq policy.
97  */
98 static int cpufreq_proc_read (
99         char                    *page,
100         char                    **start,
101         off_t                   off,
102         int                     count,
103         int                     *eof,
104         void                    *data)
105 {
106         char                    *p = page;
107         int                     len = 0;
108         struct cpufreq_policy   policy;
109         unsigned int            min_pctg = 0;
110         unsigned int            max_pctg = 0;
111         unsigned int            i = 0;
112
113         if (off != 0)
114                 goto end;
115
116         if (!warning_print) {
117                 warning_print++;
118                 printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
119                         "will be removed from (new) 2.6. kernels soon "
120                         "after 2005-01-01\n");
121         }
122
123         p += sprintf(p, "          minimum CPU frequency  -  maximum CPU frequency  -  policy\n");
124         for (i=0;i<NR_CPUS;i++) {
125                 if (!cpu_online(i))
126                         continue;
127
128                 if (cpufreq_get_policy(&policy, i))
129                         continue;
130
131                 if (!policy.cpuinfo.max_freq)
132                         continue;
133
134                 min_pctg = (policy.min * 100) / policy.cpuinfo.max_freq;
135                 max_pctg = (policy.max * 100) / policy.cpuinfo.max_freq;
136
137                 p += sprintf(p, "CPU%3d    %9d kHz (%3d %%)  -  %9d kHz (%3d %%)  -  ",
138                              i , policy.min, min_pctg, policy.max, max_pctg);
139                 if (policy.policy) {
140                         switch (policy.policy) {
141                                 case CPUFREQ_POLICY_POWERSAVE:
142                                 p += sprintf(p, "powersave\n");
143                                 break;  
144                         case CPUFREQ_POLICY_PERFORMANCE:
145                                 p += sprintf(p, "performance\n");
146                                 break;
147                         default:
148                                 p += sprintf(p, "INVALID\n");
149                                 break;
150                         } 
151                 } else
152                         p += scnprintf(p, CPUFREQ_NAME_LEN, "%s\n", policy.governor->name);
153         }
154 end:
155         len = (p - page);
156         if (len <= off+count) 
157                 *eof = 1;
158         *start = page + off;
159         len -= off;
160         if (len>count) 
161                 len = count;
162         if (len<0) 
163                 len = 0;
164
165         return len;
166 }
167
168
169 /**
170  * cpufreq_proc_write - handles writing into /proc/cpufreq
171  *
172  * This function calls the parsing script and then sets the policy
173  * accordingly.
174  */
175 static int cpufreq_proc_write (
176         struct file             *file,
177         const char              __user *buffer,
178         unsigned long           count,
179         void                    *data)
180 {
181         int                     result = 0;
182         char                    proc_string[42] = {'\0'};
183         struct cpufreq_policy   policy;
184         unsigned int            i = 0;
185
186
187         if ((count > sizeof(proc_string) - 1))
188                 return -EINVAL;
189         
190         if (copy_from_user(proc_string, buffer, count))
191                 return -EFAULT;
192
193         if (!warning_print) {
194                 warning_print++;
195                 printk(KERN_INFO "Access to /proc/cpufreq is deprecated and "
196                         "will be removed from (new) 2.6. kernels soon "
197                         "after 2005-01-01\n");
198         }
199         
200         proc_string[count] = '\0';
201
202         result = cpufreq_parse_policy(proc_string, &policy);
203         if (result)
204                 return -EFAULT;
205
206         if (policy.cpu == CPUFREQ_ALL_CPUS)
207         {
208                 for (i=0; i<NR_CPUS; i++) 
209                 {
210                         policy.cpu = i;
211                         if (cpu_online(i))
212                                 cpufreq_set_policy(&policy);
213                 }
214         } 
215         else
216                 cpufreq_set_policy(&policy);
217
218         return count;
219 }
220
221
222 /**
223  * cpufreq_proc_init - add "cpufreq" to the /proc root directory
224  *
225  * This function adds "cpufreq" to the /proc root directory.
226  */
227 static int __init cpufreq_proc_init (void)
228 {
229         struct proc_dir_entry *entry = NULL;
230
231         /* are these acceptable values? */
232         entry = create_proc_entry("cpufreq", S_IFREG|S_IRUGO|S_IWUSR, 
233                                   &proc_root);
234
235         if (!entry) {
236                 printk(KERN_ERR "unable to create /proc/cpufreq entry\n");
237                 return -EIO;
238         } else {
239                 entry->read_proc = cpufreq_proc_read;
240                 entry->write_proc = cpufreq_proc_write;
241         }
242
243         return 0;
244 }
245
246
247 /**
248  * cpufreq_proc_exit - removes "cpufreq" from the /proc root directory.
249  *
250  * This function removes "cpufreq" from the /proc root directory.
251  */
252 static void __exit cpufreq_proc_exit (void)
253 {
254         remove_proc_entry("cpufreq", &proc_root);
255         return;
256 }
257
258 MODULE_AUTHOR ("Dominik Brodowski <linux@brodo.de>");
259 MODULE_DESCRIPTION ("CPUfreq /proc/cpufreq interface");
260 MODULE_LICENSE ("GPL");
261
262 module_init(cpufreq_proc_init);
263 module_exit(cpufreq_proc_exit);