9a35456ba6b2abd9a913b57a2e2c18ef7a3995de
[linux-2.6.git] / tools / power / cpupower / lib / sysfs.c
1 /*
2  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
3  *
4  *  Licensed under the terms of the GNU GPL License version 2.
5  */
6
7 #include <stdio.h>
8 #include <errno.h>
9 #include <stdlib.h>
10 #include <string.h>
11 #include <limits.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16
17 #include "cpufreq.h"
18
19 #define PATH_TO_CPU "/sys/devices/system/cpu/"
20 #define MAX_LINE_LEN 255
21 #define SYSFS_PATH_MAX 255
22
23
24 static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
25 {
26         int fd;
27         ssize_t numread;
28
29         fd = open(path, O_RDONLY);
30         if (fd == -1)
31                 return 0;
32
33         numread = read(fd, buf, buflen - 1);
34         if (numread < 1) {
35                 close(fd);
36                 return 0;
37         }
38
39         buf[numread] = '\0';
40         close(fd);
41
42         return (unsigned int) numread;
43 }
44
45
46 /* CPUFREQ sysfs access **************************************************/
47
48 /* helper function to read file from /sys into given buffer */
49 /* fname is a relative path under "cpuX/cpufreq" dir */
50 static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
51                                             char *buf, size_t buflen)
52 {
53         char path[SYSFS_PATH_MAX];
54
55         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
56                          cpu, fname);
57         return sysfs_read_file(path, buf, buflen);
58 }
59
60 /* helper function to write a new value to a /sys file */
61 /* fname is a relative path under "cpuX/cpufreq" dir */
62 static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
63                                              const char *fname,
64                                              const char *value, size_t len)
65 {
66         char path[SYSFS_PATH_MAX];
67         int fd;
68         ssize_t numwrite;
69
70         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
71                          cpu, fname);
72
73         fd = open(path, O_WRONLY);
74         if (fd == -1)
75                 return 0;
76
77         numwrite = write(fd, value, len);
78         if (numwrite < 1) {
79                 close(fd);
80                 return 0;
81         }
82
83         close(fd);
84
85         return (unsigned int) numwrite;
86 }
87
88 /* read access to files which contain one numeric value */
89
90 enum cpufreq_value {
91         CPUINFO_CUR_FREQ,
92         CPUINFO_MIN_FREQ,
93         CPUINFO_MAX_FREQ,
94         CPUINFO_LATENCY,
95         SCALING_CUR_FREQ,
96         SCALING_MIN_FREQ,
97         SCALING_MAX_FREQ,
98         STATS_NUM_TRANSITIONS,
99         MAX_CPUFREQ_VALUE_READ_FILES
100 };
101
102 static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
103         [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
104         [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
105         [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
106         [CPUINFO_LATENCY]  = "cpuinfo_transition_latency",
107         [SCALING_CUR_FREQ] = "scaling_cur_freq",
108         [SCALING_MIN_FREQ] = "scaling_min_freq",
109         [SCALING_MAX_FREQ] = "scaling_max_freq",
110         [STATS_NUM_TRANSITIONS] = "stats/total_trans"
111 };
112
113
114 static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
115                                                  enum cpufreq_value which)
116 {
117         unsigned long value;
118         unsigned int len;
119         char linebuf[MAX_LINE_LEN];
120         char *endp;
121
122         if (which >= MAX_CPUFREQ_VALUE_READ_FILES)
123                 return 0;
124
125         len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which],
126                                 linebuf, sizeof(linebuf));
127
128         if (len == 0)
129                 return 0;
130
131         value = strtoul(linebuf, &endp, 0);
132
133         if (endp == linebuf || errno == ERANGE)
134                 return 0;
135
136         return value;
137 }
138
139 /* read access to files which contain one string */
140
141 enum cpufreq_string {
142         SCALING_DRIVER,
143         SCALING_GOVERNOR,
144         MAX_CPUFREQ_STRING_FILES
145 };
146
147 static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
148         [SCALING_DRIVER] = "scaling_driver",
149         [SCALING_GOVERNOR] = "scaling_governor",
150 };
151
152
153 static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
154                                            enum cpufreq_string which)
155 {
156         char linebuf[MAX_LINE_LEN];
157         char *result;
158         unsigned int len;
159
160         if (which >= MAX_CPUFREQ_STRING_FILES)
161                 return NULL;
162
163         len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
164                                 linebuf, sizeof(linebuf));
165         if (len == 0)
166                 return NULL;
167
168         result = strdup(linebuf);
169         if (result == NULL)
170                 return NULL;
171
172         if (result[strlen(result) - 1] == '\n')
173                 result[strlen(result) - 1] = '\0';
174
175         return result;
176 }
177
178 /* write access */
179
180 enum cpufreq_write {
181         WRITE_SCALING_MIN_FREQ,
182         WRITE_SCALING_MAX_FREQ,
183         WRITE_SCALING_GOVERNOR,
184         WRITE_SCALING_SET_SPEED,
185         MAX_CPUFREQ_WRITE_FILES
186 };
187
188 static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
189         [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
190         [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
191         [WRITE_SCALING_GOVERNOR] = "scaling_governor",
192         [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
193 };
194
195 static int sysfs_cpufreq_write_one_value(unsigned int cpu,
196                                          enum cpufreq_write which,
197                                          const char *new_value, size_t len)
198 {
199         if (which >= MAX_CPUFREQ_WRITE_FILES)
200                 return 0;
201
202         if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
203                                         new_value, len) != len)
204                 return -ENODEV;
205
206         return 0;
207 };
208
209 unsigned long sysfs_get_freq_kernel(unsigned int cpu)
210 {
211         return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
212 }
213
214 unsigned long sysfs_get_freq_hardware(unsigned int cpu)
215 {
216         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
217 }
218
219 unsigned long sysfs_get_freq_transition_latency(unsigned int cpu)
220 {
221         return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
222 }
223
224 int sysfs_get_freq_hardware_limits(unsigned int cpu,
225                               unsigned long *min,
226                               unsigned long *max)
227 {
228         if ((!min) || (!max))
229                 return -EINVAL;
230
231         *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
232         if (!*min)
233                 return -ENODEV;
234
235         *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
236         if (!*max)
237                 return -ENODEV;
238
239         return 0;
240 }
241
242 char *sysfs_get_freq_driver(unsigned int cpu)
243 {
244         return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
245 }
246
247 struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu)
248 {
249         struct cpufreq_policy *policy;
250
251         policy = malloc(sizeof(struct cpufreq_policy));
252         if (!policy)
253                 return NULL;
254
255         policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
256         if (!policy->governor) {
257                 free(policy);
258                 return NULL;
259         }
260         policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
261         policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
262         if ((!policy->min) || (!policy->max)) {
263                 free(policy->governor);
264                 free(policy);
265                 return NULL;
266         }
267
268         return policy;
269 }
270
271 struct cpufreq_available_governors *
272 sysfs_get_freq_available_governors(unsigned int cpu) {
273         struct cpufreq_available_governors *first = NULL;
274         struct cpufreq_available_governors *current = NULL;
275         char linebuf[MAX_LINE_LEN];
276         unsigned int pos, i;
277         unsigned int len;
278
279         len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
280                                 linebuf, sizeof(linebuf));
281         if (len == 0)
282                 return NULL;
283
284         pos = 0;
285         for (i = 0; i < len; i++) {
286                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
287                         if (i - pos < 2)
288                                 continue;
289                         if (current) {
290                                 current->next = malloc(sizeof(*current));
291                                 if (!current->next)
292                                         goto error_out;
293                                 current = current->next;
294                         } else {
295                                 first = malloc(sizeof(*first));
296                                 if (!first)
297                                         goto error_out;
298                                 current = first;
299                         }
300                         current->first = first;
301                         current->next = NULL;
302
303                         current->governor = malloc(i - pos + 1);
304                         if (!current->governor)
305                                 goto error_out;
306
307                         memcpy(current->governor, linebuf + pos, i - pos);
308                         current->governor[i - pos] = '\0';
309                         pos = i + 1;
310                 }
311         }
312
313         return first;
314
315  error_out:
316         while (first) {
317                 current = first->next;
318                 if (first->governor)
319                         free(first->governor);
320                 free(first);
321                 first = current;
322         }
323         return NULL;
324 }
325
326
327 struct cpufreq_available_frequencies *
328 sysfs_get_available_frequencies(unsigned int cpu) {
329         struct cpufreq_available_frequencies *first = NULL;
330         struct cpufreq_available_frequencies *current = NULL;
331         char one_value[SYSFS_PATH_MAX];
332         char linebuf[MAX_LINE_LEN];
333         unsigned int pos, i;
334         unsigned int len;
335
336         len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
337                                 linebuf, sizeof(linebuf));
338         if (len == 0)
339                 return NULL;
340
341         pos = 0;
342         for (i = 0; i < len; i++) {
343                 if (linebuf[i] == ' ' || linebuf[i] == '\n') {
344                         if (i - pos < 2)
345                                 continue;
346                         if (i - pos >= SYSFS_PATH_MAX)
347                                 goto error_out;
348                         if (current) {
349                                 current->next = malloc(sizeof(*current));
350                                 if (!current->next)
351                                         goto error_out;
352                                 current = current->next;
353                         } else {
354                                 first = malloc(sizeof(*first));
355                                 if (!first)
356                                         goto error_out;
357                                 current = first;
358                         }
359                         current->first = first;
360                         current->next = NULL;
361
362                         memcpy(one_value, linebuf + pos, i - pos);
363                         one_value[i - pos] = '\0';
364                         if (sscanf(one_value, "%lu", &current->frequency) != 1)
365                                 goto error_out;
366
367                         pos = i + 1;
368                 }
369         }
370
371         return first;
372
373  error_out:
374         while (first) {
375                 current = first->next;
376                 free(first);
377                 first = current;
378         }
379         return NULL;
380 }
381
382 static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
383                                                         const char *file)
384 {
385         struct cpufreq_affected_cpus *first = NULL;
386         struct cpufreq_affected_cpus *current = NULL;
387         char one_value[SYSFS_PATH_MAX];
388         char linebuf[MAX_LINE_LEN];
389         unsigned int pos, i;
390         unsigned int len;
391
392         len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
393         if (len == 0)
394                 return NULL;
395
396         pos = 0;
397         for (i = 0; i < len; i++) {
398                 if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
399                         if (i - pos  < 1)
400                                 continue;
401                         if (i - pos >= SYSFS_PATH_MAX)
402                                 goto error_out;
403                         if (current) {
404                                 current->next = malloc(sizeof(*current));
405                                 if (!current->next)
406                                         goto error_out;
407                                 current = current->next;
408                         } else {
409                                 first = malloc(sizeof(*first));
410                                 if (!first)
411                                         goto error_out;
412                                 current = first;
413                         }
414                         current->first = first;
415                         current->next = NULL;
416
417                         memcpy(one_value, linebuf + pos, i - pos);
418                         one_value[i - pos] = '\0';
419
420                         if (sscanf(one_value, "%u", &current->cpu) != 1)
421                                 goto error_out;
422
423                         pos = i + 1;
424                 }
425         }
426
427         return first;
428
429  error_out:
430         while (first) {
431                 current = first->next;
432                 free(first);
433                 first = current;
434         }
435         return NULL;
436 }
437
438 struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu)
439 {
440         return sysfs_get_cpu_list(cpu, "affected_cpus");
441 }
442
443 struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu)
444 {
445         return sysfs_get_cpu_list(cpu, "related_cpus");
446 }
447
448 struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu,
449                                         unsigned long long *total_time) {
450         struct cpufreq_stats *first = NULL;
451         struct cpufreq_stats *current = NULL;
452         char one_value[SYSFS_PATH_MAX];
453         char linebuf[MAX_LINE_LEN];
454         unsigned int pos, i;
455         unsigned int len;
456
457         len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
458                                 linebuf, sizeof(linebuf));
459         if (len == 0)
460                 return NULL;
461
462         *total_time = 0;
463         pos = 0;
464         for (i = 0; i < len; i++) {
465                 if (i == strlen(linebuf) || linebuf[i] == '\n') {
466                         if (i - pos < 2)
467                                 continue;
468                         if ((i - pos) >= SYSFS_PATH_MAX)
469                                 goto error_out;
470                         if (current) {
471                                 current->next = malloc(sizeof(*current));
472                                 if (!current->next)
473                                         goto error_out;
474                                 current = current->next;
475                         } else {
476                                 first = malloc(sizeof(*first));
477                                 if (!first)
478                                         goto error_out;
479                                 current = first;
480                         }
481                         current->first = first;
482                         current->next = NULL;
483
484                         memcpy(one_value, linebuf + pos, i - pos);
485                         one_value[i - pos] = '\0';
486                         if (sscanf(one_value, "%lu %llu",
487                                         &current->frequency,
488                                         &current->time_in_state) != 2)
489                                 goto error_out;
490
491                         *total_time = *total_time + current->time_in_state;
492                         pos = i + 1;
493                 }
494         }
495
496         return first;
497
498  error_out:
499         while (first) {
500                 current = first->next;
501                 free(first);
502                 first = current;
503         }
504         return NULL;
505 }
506
507 unsigned long sysfs_get_freq_transitions(unsigned int cpu)
508 {
509         return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
510 }
511
512 static int verify_gov(char *new_gov, char *passed_gov)
513 {
514         unsigned int i, j = 0;
515
516         if (!passed_gov || (strlen(passed_gov) > 19))
517                 return -EINVAL;
518
519         strncpy(new_gov, passed_gov, 20);
520         for (i = 0; i < 20; i++) {
521                 if (j) {
522                         new_gov[i] = '\0';
523                         continue;
524                 }
525                 if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
526                         continue;
527
528                 if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
529                         continue;
530
531                 if (new_gov[i] == '-')
532                         continue;
533
534                 if (new_gov[i] == '_')
535                         continue;
536
537                 if (new_gov[i] == '\0') {
538                         j = 1;
539                         continue;
540                 }
541                 return -EINVAL;
542         }
543         new_gov[19] = '\0';
544         return 0;
545 }
546
547 int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor)
548 {
549         char new_gov[SYSFS_PATH_MAX];
550
551         if (!governor)
552                 return -EINVAL;
553
554         if (verify_gov(new_gov, governor))
555                 return -EINVAL;
556
557         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
558                                              new_gov, strlen(new_gov));
559 };
560
561 int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq)
562 {
563         char value[SYSFS_PATH_MAX];
564
565         snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
566
567         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
568                                              value, strlen(value));
569 };
570
571
572 int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq)
573 {
574         char value[SYSFS_PATH_MAX];
575
576         snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
577
578         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
579                                              value, strlen(value));
580 };
581
582
583 int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy)
584 {
585         char min[SYSFS_PATH_MAX];
586         char max[SYSFS_PATH_MAX];
587         char gov[SYSFS_PATH_MAX];
588         int ret;
589         unsigned long old_min;
590         int write_max_first;
591
592         if (!policy || !(policy->governor))
593                 return -EINVAL;
594
595         if (policy->max < policy->min)
596                 return -EINVAL;
597
598         if (verify_gov(gov, policy->governor))
599                 return -EINVAL;
600
601         snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
602         snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
603
604         old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
605         write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
606
607         if (write_max_first) {
608                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
609                                                     max, strlen(max));
610                 if (ret)
611                         return ret;
612         }
613
614         ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
615                                             strlen(min));
616         if (ret)
617                 return ret;
618
619         if (!write_max_first) {
620                 ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
621                                                     max, strlen(max));
622                 if (ret)
623                         return ret;
624         }
625
626         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
627                                              gov, strlen(gov));
628 }
629
630 int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency)
631 {
632         struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu);
633         char userspace_gov[] = "userspace";
634         char freq[SYSFS_PATH_MAX];
635         int ret;
636
637         if (!pol)
638                 return -ENODEV;
639
640         if (strncmp(pol->governor, userspace_gov, 9) != 0) {
641                 ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov);
642                 if (ret) {
643                         cpufreq_put_policy(pol);
644                         return ret;
645                 }
646         }
647
648         cpufreq_put_policy(pol);
649
650         snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
651
652         return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
653                                              freq, strlen(freq));
654 }
655
656 /* CPUFREQ sysfs access **************************************************/
657
658 /* General sysfs access **************************************************/
659 int sysfs_cpu_exists(unsigned int cpu)
660 {
661         char file[SYSFS_PATH_MAX];
662         struct stat statbuf;
663
664         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu);
665
666         if (stat(file, &statbuf) != 0)
667                 return -ENOSYS;
668
669         return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS;
670 }
671
672 /* General sysfs access **************************************************/