2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
4 * Licensed under the terms of the GNU GPL License version 2.
12 #include <sys/types.h>
19 #define PATH_TO_CPU "/sys/devices/system/cpu/"
20 #define MAX_LINE_LEN 255
21 #define SYSFS_PATH_MAX 255
24 static unsigned int sysfs_read_file(const char *path
, char *buf
, size_t buflen
)
29 if ( ( fd
= open(path
, O_RDONLY
) ) == -1 )
32 numread
= read(fd
, buf
, buflen
- 1);
46 /* CPUFREQ sysfs access **************************************************/
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
)
53 char path
[SYSFS_PATH_MAX
];
55 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpufreq/%s",
57 return sysfs_read_file(path
, buf
, buflen
);
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
,
64 const char *value
, size_t len
)
66 char path
[SYSFS_PATH_MAX
];
70 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpufreq/%s",
73 if ( ( fd
= open(path
, O_WRONLY
) ) == -1 )
76 numwrite
= write(fd
, value
, len
);
88 /* read access to files which contain one numeric value */
98 STATS_NUM_TRANSITIONS
,
99 MAX_CPUFREQ_VALUE_READ_FILES
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"
114 static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu
,
115 enum cpufreq_value which
)
119 char linebuf
[MAX_LINE_LEN
];
122 if ( which
>= MAX_CPUFREQ_VALUE_READ_FILES
)
125 if ( ( len
= sysfs_cpufreq_read_file(cpu
, cpufreq_value_files
[which
],
126 linebuf
, sizeof(linebuf
))) == 0 )
129 value
= strtoul(linebuf
, &endp
, 0);
131 if ( endp
== linebuf
|| errno
== ERANGE
)
137 /* read access to files which contain one string */
139 enum cpufreq_string
{
142 MAX_CPUFREQ_STRING_FILES
145 static const char *cpufreq_string_files
[MAX_CPUFREQ_STRING_FILES
] = {
146 [SCALING_DRIVER
] = "scaling_driver",
147 [SCALING_GOVERNOR
] = "scaling_governor",
151 static char * sysfs_cpufreq_get_one_string(unsigned int cpu
,
152 enum cpufreq_string which
)
154 char linebuf
[MAX_LINE_LEN
];
158 if (which
>= MAX_CPUFREQ_STRING_FILES
)
161 if ( ( len
= sysfs_cpufreq_read_file(cpu
, cpufreq_string_files
[which
],
162 linebuf
, sizeof(linebuf
))) == 0 )
165 if ( ( result
= strdup(linebuf
) ) == NULL
)
168 if (result
[strlen(result
) - 1] == '\n')
169 result
[strlen(result
) - 1] = '\0';
177 WRITE_SCALING_MIN_FREQ
,
178 WRITE_SCALING_MAX_FREQ
,
179 WRITE_SCALING_GOVERNOR
,
180 WRITE_SCALING_SET_SPEED
,
181 MAX_CPUFREQ_WRITE_FILES
184 static const char *cpufreq_write_files
[MAX_CPUFREQ_WRITE_FILES
] = {
185 [WRITE_SCALING_MIN_FREQ
] = "scaling_min_freq",
186 [WRITE_SCALING_MAX_FREQ
] = "scaling_max_freq",
187 [WRITE_SCALING_GOVERNOR
] = "scaling_governor",
188 [WRITE_SCALING_SET_SPEED
] = "scaling_setspeed",
191 static int sysfs_cpufreq_write_one_value(unsigned int cpu
,
192 enum cpufreq_write which
,
193 const char *new_value
, size_t len
)
195 if (which
>= MAX_CPUFREQ_WRITE_FILES
)
198 if ( sysfs_cpufreq_write_file(cpu
, cpufreq_write_files
[which
],
199 new_value
, len
) != len
)
205 unsigned long sysfs_get_freq_kernel(unsigned int cpu
)
207 return sysfs_cpufreq_get_one_value(cpu
, SCALING_CUR_FREQ
);
210 unsigned long sysfs_get_freq_hardware(unsigned int cpu
)
212 return sysfs_cpufreq_get_one_value(cpu
, CPUINFO_CUR_FREQ
);
215 unsigned long sysfs_get_freq_transition_latency(unsigned int cpu
)
217 return sysfs_cpufreq_get_one_value(cpu
, CPUINFO_LATENCY
);
220 int sysfs_get_freq_hardware_limits(unsigned int cpu
,
224 if ((!min
) || (!max
))
227 *min
= sysfs_cpufreq_get_one_value(cpu
, CPUINFO_MIN_FREQ
);
231 *max
= sysfs_cpufreq_get_one_value(cpu
, CPUINFO_MAX_FREQ
);
238 char * sysfs_get_freq_driver(unsigned int cpu
) {
239 return sysfs_cpufreq_get_one_string(cpu
, SCALING_DRIVER
);
242 struct cpufreq_policy
* sysfs_get_freq_policy(unsigned int cpu
) {
243 struct cpufreq_policy
*policy
;
245 policy
= malloc(sizeof(struct cpufreq_policy
));
249 policy
->governor
= sysfs_cpufreq_get_one_string(cpu
, SCALING_GOVERNOR
);
250 if (!policy
->governor
) {
254 policy
->min
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MIN_FREQ
);
255 policy
->max
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MAX_FREQ
);
256 if ((!policy
->min
) || (!policy
->max
)) {
257 free(policy
->governor
);
265 struct cpufreq_available_governors
*
266 sysfs_get_freq_available_governors(unsigned int cpu
) {
267 struct cpufreq_available_governors
*first
= NULL
;
268 struct cpufreq_available_governors
*current
= NULL
;
269 char linebuf
[MAX_LINE_LEN
];
273 if ( ( len
= sysfs_cpufreq_read_file(cpu
, "scaling_available_governors",
274 linebuf
, sizeof(linebuf
))) == 0 )
280 for ( i
= 0; i
< len
; i
++ )
282 if ( linebuf
[i
] == ' ' || linebuf
[i
] == '\n' )
287 current
->next
= malloc(sizeof *current
);
288 if ( ! current
->next
)
290 current
= current
->next
;
292 first
= malloc( sizeof *first
);
297 current
->first
= first
;
298 current
->next
= NULL
;
300 current
->governor
= malloc(i
- pos
+ 1);
301 if ( ! current
->governor
)
304 memcpy( current
->governor
, linebuf
+ pos
, i
- pos
);
305 current
->governor
[i
- pos
] = '\0';
314 current
= first
->next
;
315 if ( first
->governor
)
316 free( first
->governor
);
324 struct cpufreq_available_frequencies
*
325 sysfs_get_available_frequencies(unsigned int cpu
) {
326 struct cpufreq_available_frequencies
*first
= NULL
;
327 struct cpufreq_available_frequencies
*current
= NULL
;
328 char one_value
[SYSFS_PATH_MAX
];
329 char linebuf
[MAX_LINE_LEN
];
333 if ( ( len
= sysfs_cpufreq_read_file(cpu
,
334 "scaling_available_frequencies",
335 linebuf
, sizeof(linebuf
))) == 0 )
341 for ( i
= 0; i
< len
; i
++ )
343 if ( linebuf
[i
] == ' ' || linebuf
[i
] == '\n' )
347 if ( i
- pos
>= SYSFS_PATH_MAX
)
350 current
->next
= malloc(sizeof *current
);
351 if ( ! current
->next
)
353 current
= current
->next
;
355 first
= malloc(sizeof *first
);
360 current
->first
= first
;
361 current
->next
= NULL
;
363 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
364 one_value
[i
- pos
] = '\0';
365 if ( sscanf(one_value
, "%lu", ¤t
->frequency
) != 1 )
376 current
= first
->next
;
383 static struct cpufreq_affected_cpus
* sysfs_get_cpu_list(unsigned int cpu
,
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
];
392 if ( ( len
= sysfs_cpufreq_read_file(cpu
, file
, linebuf
,
393 sizeof(linebuf
))) == 0 )
399 for ( i
= 0; i
< len
; i
++ )
401 if ( i
== len
|| linebuf
[i
] == ' ' || linebuf
[i
] == '\n' )
405 if ( i
- pos
>= SYSFS_PATH_MAX
)
408 current
->next
= malloc(sizeof *current
);
409 if ( ! current
->next
)
411 current
= current
->next
;
413 first
= malloc(sizeof *first
);
418 current
->first
= first
;
419 current
->next
= NULL
;
421 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
422 one_value
[i
- pos
] = '\0';
424 if ( sscanf(one_value
, "%u", ¤t
->cpu
) != 1 )
435 current
= first
->next
;
442 struct cpufreq_affected_cpus
* sysfs_get_freq_affected_cpus(unsigned int cpu
) {
443 return sysfs_get_cpu_list(cpu
, "affected_cpus");
446 struct cpufreq_affected_cpus
* sysfs_get_freq_related_cpus(unsigned int cpu
) {
447 return sysfs_get_cpu_list(cpu
, "related_cpus");
450 struct cpufreq_stats
* sysfs_get_freq_stats(unsigned int cpu
, unsigned long long *total_time
) {
451 struct cpufreq_stats
*first
= NULL
;
452 struct cpufreq_stats
*current
= NULL
;
453 char one_value
[SYSFS_PATH_MAX
];
454 char linebuf
[MAX_LINE_LEN
];
458 if ( ( len
= sysfs_cpufreq_read_file(cpu
, "stats/time_in_state",
459 linebuf
, sizeof(linebuf
))) == 0 )
464 for ( i
= 0; i
< len
; i
++ )
466 if ( i
== strlen(linebuf
) || linebuf
[i
] == '\n' )
470 if ( (i
- pos
) >= SYSFS_PATH_MAX
)
473 current
->next
= malloc(sizeof *current
);
474 if ( ! current
->next
)
476 current
= current
->next
;
478 first
= malloc(sizeof *first
);
483 current
->first
= first
;
484 current
->next
= NULL
;
486 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
487 one_value
[i
- pos
] = '\0';
488 if ( sscanf(one_value
, "%lu %llu", ¤t
->frequency
, ¤t
->time_in_state
) != 2 )
491 *total_time
= *total_time
+ current
->time_in_state
;
500 current
= first
->next
;
507 unsigned long sysfs_get_freq_transitions(unsigned int cpu
)
509 return sysfs_cpufreq_get_one_value(cpu
, STATS_NUM_TRANSITIONS
);
512 static int verify_gov(char *new_gov
, char *passed_gov
)
516 if (!passed_gov
|| (strlen(passed_gov
) > 19))
519 strncpy(new_gov
, passed_gov
, 20);
525 if ((new_gov
[i
] >= 'a') && (new_gov
[i
] <= 'z')) {
528 if ((new_gov
[i
] >= 'A') && (new_gov
[i
] <= 'Z')) {
531 if (new_gov
[i
] == '-') {
534 if (new_gov
[i
] == '_') {
537 if (new_gov
[i
] == '\0') {
547 int sysfs_modify_freq_policy_governor(unsigned int cpu
, char *governor
)
549 char new_gov
[SYSFS_PATH_MAX
];
554 if (verify_gov(new_gov
, governor
))
557 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_GOVERNOR
,
558 new_gov
, strlen(new_gov
));
561 int sysfs_modify_freq_policy_max(unsigned int cpu
, unsigned long max_freq
)
563 char value
[SYSFS_PATH_MAX
];
565 snprintf(value
, SYSFS_PATH_MAX
, "%lu", max_freq
);
567 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
568 value
, strlen(value
));
572 int sysfs_modify_freq_policy_min(unsigned int cpu
, unsigned long min_freq
)
574 char value
[SYSFS_PATH_MAX
];
576 snprintf(value
, SYSFS_PATH_MAX
, "%lu", min_freq
);
578 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MIN_FREQ
,
579 value
, strlen(value
));
583 int sysfs_set_freq_policy(unsigned int cpu
, struct cpufreq_policy
*policy
)
585 char min
[SYSFS_PATH_MAX
];
586 char max
[SYSFS_PATH_MAX
];
587 char gov
[SYSFS_PATH_MAX
];
589 unsigned long old_min
;
592 if (!policy
|| !(policy
->governor
))
595 if (policy
->max
< policy
->min
)
598 if (verify_gov(gov
, policy
->governor
))
601 snprintf(min
, SYSFS_PATH_MAX
, "%lu", policy
->min
);
602 snprintf(max
, SYSFS_PATH_MAX
, "%lu", policy
->max
);
604 old_min
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MIN_FREQ
);
605 write_max_first
= (old_min
&& (policy
->max
< old_min
) ? 0 : 1);
607 if (write_max_first
) {
608 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
614 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MIN_FREQ
, min
,
619 if (!write_max_first
) {
620 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
626 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_GOVERNOR
,
630 int sysfs_set_frequency(unsigned int cpu
, unsigned long target_frequency
) {
631 struct cpufreq_policy
*pol
= sysfs_get_freq_policy(cpu
);
632 char userspace_gov
[] = "userspace";
633 char freq
[SYSFS_PATH_MAX
];
639 if (strncmp(pol
->governor
, userspace_gov
, 9) != 0) {
640 ret
= sysfs_modify_freq_policy_governor(cpu
, userspace_gov
);
642 cpufreq_put_policy(pol
);
647 cpufreq_put_policy(pol
);
649 snprintf(freq
, SYSFS_PATH_MAX
, "%lu", target_frequency
);
651 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_SET_SPEED
,
655 /* CPUFREQ sysfs access **************************************************/
657 /* General sysfs access **************************************************/
658 int sysfs_cpu_exists(unsigned int cpu
)
660 char file
[SYSFS_PATH_MAX
];
663 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpu%u/", cpu
);
665 if ( stat(file
, &statbuf
) != 0 )
668 return S_ISDIR(statbuf
.st_mode
) ? 0 : -ENOSYS
;
671 /* General sysfs access **************************************************/