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>
18 #include "cpupower_intern.h"
20 /* CPUFREQ sysfs access **************************************************/
22 /* helper function to read file from /sys into given buffer */
23 /* fname is a relative path under "cpuX/cpufreq" dir */
24 static unsigned int sysfs_cpufreq_read_file(unsigned int cpu
, const char *fname
,
25 char *buf
, size_t buflen
)
27 char path
[SYSFS_PATH_MAX
];
29 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpufreq/%s",
31 return sysfs_read_file(path
, buf
, buflen
);
34 /* helper function to write a new value to a /sys file */
35 /* fname is a relative path under "cpuX/cpufreq" dir */
36 static unsigned int sysfs_cpufreq_write_file(unsigned int cpu
,
38 const char *value
, size_t len
)
40 char path
[SYSFS_PATH_MAX
];
44 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpufreq/%s",
47 fd
= open(path
, O_WRONLY
);
51 numwrite
= write(fd
, value
, len
);
59 return (unsigned int) numwrite
;
62 /* read access to files which contain one numeric value */
72 STATS_NUM_TRANSITIONS
,
73 MAX_CPUFREQ_VALUE_READ_FILES
76 static const char *cpufreq_value_files
[MAX_CPUFREQ_VALUE_READ_FILES
] = {
77 [CPUINFO_CUR_FREQ
] = "cpuinfo_cur_freq",
78 [CPUINFO_MIN_FREQ
] = "cpuinfo_min_freq",
79 [CPUINFO_MAX_FREQ
] = "cpuinfo_max_freq",
80 [CPUINFO_LATENCY
] = "cpuinfo_transition_latency",
81 [SCALING_CUR_FREQ
] = "scaling_cur_freq",
82 [SCALING_MIN_FREQ
] = "scaling_min_freq",
83 [SCALING_MAX_FREQ
] = "scaling_max_freq",
84 [STATS_NUM_TRANSITIONS
] = "stats/total_trans"
88 static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu
,
89 enum cpufreq_value which
)
93 char linebuf
[MAX_LINE_LEN
];
96 if (which
>= MAX_CPUFREQ_VALUE_READ_FILES
)
99 len
= sysfs_cpufreq_read_file(cpu
, cpufreq_value_files
[which
],
100 linebuf
, sizeof(linebuf
));
105 value
= strtoul(linebuf
, &endp
, 0);
107 if (endp
== linebuf
|| errno
== ERANGE
)
113 /* read access to files which contain one string */
115 enum cpufreq_string
{
118 MAX_CPUFREQ_STRING_FILES
121 static const char *cpufreq_string_files
[MAX_CPUFREQ_STRING_FILES
] = {
122 [SCALING_DRIVER
] = "scaling_driver",
123 [SCALING_GOVERNOR
] = "scaling_governor",
127 static char *sysfs_cpufreq_get_one_string(unsigned int cpu
,
128 enum cpufreq_string which
)
130 char linebuf
[MAX_LINE_LEN
];
134 if (which
>= MAX_CPUFREQ_STRING_FILES
)
137 len
= sysfs_cpufreq_read_file(cpu
, cpufreq_string_files
[which
],
138 linebuf
, sizeof(linebuf
));
142 result
= strdup(linebuf
);
146 if (result
[strlen(result
) - 1] == '\n')
147 result
[strlen(result
) - 1] = '\0';
155 WRITE_SCALING_MIN_FREQ
,
156 WRITE_SCALING_MAX_FREQ
,
157 WRITE_SCALING_GOVERNOR
,
158 WRITE_SCALING_SET_SPEED
,
159 MAX_CPUFREQ_WRITE_FILES
162 static const char *cpufreq_write_files
[MAX_CPUFREQ_WRITE_FILES
] = {
163 [WRITE_SCALING_MIN_FREQ
] = "scaling_min_freq",
164 [WRITE_SCALING_MAX_FREQ
] = "scaling_max_freq",
165 [WRITE_SCALING_GOVERNOR
] = "scaling_governor",
166 [WRITE_SCALING_SET_SPEED
] = "scaling_setspeed",
169 static int sysfs_cpufreq_write_one_value(unsigned int cpu
,
170 enum cpufreq_write which
,
171 const char *new_value
, size_t len
)
173 if (which
>= MAX_CPUFREQ_WRITE_FILES
)
176 if (sysfs_cpufreq_write_file(cpu
, cpufreq_write_files
[which
],
177 new_value
, len
) != len
)
183 unsigned long cpufreq_get_freq_kernel(unsigned int cpu
)
185 return sysfs_cpufreq_get_one_value(cpu
, SCALING_CUR_FREQ
);
188 unsigned long cpufreq_get_freq_hardware(unsigned int cpu
)
190 return sysfs_cpufreq_get_one_value(cpu
, CPUINFO_CUR_FREQ
);
193 unsigned long cpufreq_get_transition_latency(unsigned int cpu
)
195 return sysfs_cpufreq_get_one_value(cpu
, CPUINFO_LATENCY
);
198 int cpufreq_get_hardware_limits(unsigned int cpu
,
202 if ((!min
) || (!max
))
205 *min
= sysfs_cpufreq_get_one_value(cpu
, CPUINFO_MIN_FREQ
);
209 *max
= sysfs_cpufreq_get_one_value(cpu
, CPUINFO_MAX_FREQ
);
216 char *cpufreq_get_driver(unsigned int cpu
)
218 return sysfs_cpufreq_get_one_string(cpu
, SCALING_DRIVER
);
221 void cpufreq_put_driver(char *ptr
)
228 struct cpufreq_policy
*cpufreq_get_policy(unsigned int cpu
)
230 struct cpufreq_policy
*policy
;
232 policy
= malloc(sizeof(struct cpufreq_policy
));
236 policy
->governor
= sysfs_cpufreq_get_one_string(cpu
, SCALING_GOVERNOR
);
237 if (!policy
->governor
) {
241 policy
->min
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MIN_FREQ
);
242 policy
->max
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MAX_FREQ
);
243 if ((!policy
->min
) || (!policy
->max
)) {
244 free(policy
->governor
);
252 void cpufreq_put_policy(struct cpufreq_policy
*policy
)
254 if ((!policy
) || (!policy
->governor
))
257 free(policy
->governor
);
258 policy
->governor
= NULL
;
262 struct cpufreq_available_governors
*cpufreq_get_available_governors(unsigned
265 struct cpufreq_available_governors
*first
= NULL
;
266 struct cpufreq_available_governors
*current
= NULL
;
267 char linebuf
[MAX_LINE_LEN
];
271 len
= sysfs_cpufreq_read_file(cpu
, "scaling_available_governors",
272 linebuf
, sizeof(linebuf
));
277 for (i
= 0; i
< len
; i
++) {
278 if (linebuf
[i
] == ' ' || linebuf
[i
] == '\n') {
282 current
->next
= malloc(sizeof(*current
));
285 current
= current
->next
;
287 first
= malloc(sizeof(*first
));
292 current
->first
= first
;
293 current
->next
= NULL
;
295 current
->governor
= malloc(i
- pos
+ 1);
296 if (!current
->governor
)
299 memcpy(current
->governor
, linebuf
+ pos
, i
- pos
);
300 current
->governor
[i
- pos
] = '\0';
309 current
= first
->next
;
311 free(first
->governor
);
318 void cpufreq_put_available_governors(struct cpufreq_available_governors
*any
)
320 struct cpufreq_available_governors
*tmp
, *next
;
336 struct cpufreq_available_frequencies
337 *cpufreq_get_available_frequencies(unsigned int cpu
)
339 struct cpufreq_available_frequencies
*first
= NULL
;
340 struct cpufreq_available_frequencies
*current
= NULL
;
341 char one_value
[SYSFS_PATH_MAX
];
342 char linebuf
[MAX_LINE_LEN
];
346 len
= sysfs_cpufreq_read_file(cpu
, "scaling_available_frequencies",
347 linebuf
, sizeof(linebuf
));
352 for (i
= 0; i
< len
; i
++) {
353 if (linebuf
[i
] == ' ' || linebuf
[i
] == '\n') {
356 if (i
- pos
>= SYSFS_PATH_MAX
)
359 current
->next
= malloc(sizeof(*current
));
362 current
= current
->next
;
364 first
= malloc(sizeof(*first
));
369 current
->first
= first
;
370 current
->next
= NULL
;
372 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
373 one_value
[i
- pos
] = '\0';
374 if (sscanf(one_value
, "%lu", ¤t
->frequency
) != 1)
385 current
= first
->next
;
392 void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies
394 struct cpufreq_available_frequencies
*tmp
, *next
;
407 static struct cpufreq_affected_cpus
*sysfs_get_cpu_list(unsigned int cpu
,
410 struct cpufreq_affected_cpus
*first
= NULL
;
411 struct cpufreq_affected_cpus
*current
= NULL
;
412 char one_value
[SYSFS_PATH_MAX
];
413 char linebuf
[MAX_LINE_LEN
];
417 len
= sysfs_cpufreq_read_file(cpu
, file
, linebuf
, sizeof(linebuf
));
422 for (i
= 0; i
< len
; i
++) {
423 if (i
== len
|| linebuf
[i
] == ' ' || linebuf
[i
] == '\n') {
426 if (i
- pos
>= SYSFS_PATH_MAX
)
429 current
->next
= malloc(sizeof(*current
));
432 current
= current
->next
;
434 first
= malloc(sizeof(*first
));
439 current
->first
= first
;
440 current
->next
= NULL
;
442 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
443 one_value
[i
- pos
] = '\0';
445 if (sscanf(one_value
, "%u", ¤t
->cpu
) != 1)
456 current
= first
->next
;
463 struct cpufreq_affected_cpus
*cpufreq_get_affected_cpus(unsigned int cpu
)
465 return sysfs_get_cpu_list(cpu
, "affected_cpus");
468 void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus
*any
)
470 struct cpufreq_affected_cpus
*tmp
, *next
;
484 struct cpufreq_affected_cpus
*cpufreq_get_related_cpus(unsigned int cpu
)
486 return sysfs_get_cpu_list(cpu
, "related_cpus");
489 void cpufreq_put_related_cpus(struct cpufreq_affected_cpus
*any
)
491 cpufreq_put_affected_cpus(any
);
494 static int verify_gov(char *new_gov
, char *passed_gov
)
496 unsigned int i
, j
= 0;
498 if (!passed_gov
|| (strlen(passed_gov
) > 19))
501 strncpy(new_gov
, passed_gov
, 20);
502 for (i
= 0; i
< 20; i
++) {
507 if ((new_gov
[i
] >= 'a') && (new_gov
[i
] <= 'z'))
510 if ((new_gov
[i
] >= 'A') && (new_gov
[i
] <= 'Z'))
513 if (new_gov
[i
] == '-')
516 if (new_gov
[i
] == '_')
519 if (new_gov
[i
] == '\0') {
529 int cpufreq_set_policy(unsigned int cpu
, struct cpufreq_policy
*policy
)
531 char min
[SYSFS_PATH_MAX
];
532 char max
[SYSFS_PATH_MAX
];
533 char gov
[SYSFS_PATH_MAX
];
535 unsigned long old_min
;
538 if (!policy
|| !(policy
->governor
))
541 if (policy
->max
< policy
->min
)
544 if (verify_gov(gov
, policy
->governor
))
547 snprintf(min
, SYSFS_PATH_MAX
, "%lu", policy
->min
);
548 snprintf(max
, SYSFS_PATH_MAX
, "%lu", policy
->max
);
550 old_min
= sysfs_cpufreq_get_one_value(cpu
, SCALING_MIN_FREQ
);
551 write_max_first
= (old_min
&& (policy
->max
< old_min
) ? 0 : 1);
553 if (write_max_first
) {
554 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
560 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MIN_FREQ
, min
,
565 if (!write_max_first
) {
566 ret
= sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
572 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_GOVERNOR
,
577 int cpufreq_modify_policy_min(unsigned int cpu
, unsigned long min_freq
)
579 char value
[SYSFS_PATH_MAX
];
581 snprintf(value
, SYSFS_PATH_MAX
, "%lu", min_freq
);
583 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MIN_FREQ
,
584 value
, strlen(value
));
588 int cpufreq_modify_policy_max(unsigned int cpu
, unsigned long max_freq
)
590 char value
[SYSFS_PATH_MAX
];
592 snprintf(value
, SYSFS_PATH_MAX
, "%lu", max_freq
);
594 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_MAX_FREQ
,
595 value
, strlen(value
));
598 int cpufreq_modify_policy_governor(unsigned int cpu
, char *governor
)
600 char new_gov
[SYSFS_PATH_MAX
];
602 if ((!governor
) || (strlen(governor
) > 19))
605 if (verify_gov(new_gov
, governor
))
608 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_GOVERNOR
,
609 new_gov
, strlen(new_gov
));
612 int cpufreq_set_frequency(unsigned int cpu
, unsigned long target_frequency
)
614 struct cpufreq_policy
*pol
= cpufreq_get_policy(cpu
);
615 char userspace_gov
[] = "userspace";
616 char freq
[SYSFS_PATH_MAX
];
622 if (strncmp(pol
->governor
, userspace_gov
, 9) != 0) {
623 ret
= cpufreq_modify_policy_governor(cpu
, userspace_gov
);
625 cpufreq_put_policy(pol
);
630 cpufreq_put_policy(pol
);
632 snprintf(freq
, SYSFS_PATH_MAX
, "%lu", target_frequency
);
634 return sysfs_cpufreq_write_one_value(cpu
, WRITE_SCALING_SET_SPEED
,
638 struct cpufreq_stats
*cpufreq_get_stats(unsigned int cpu
,
639 unsigned long long *total_time
)
641 struct cpufreq_stats
*first
= NULL
;
642 struct cpufreq_stats
*current
= NULL
;
643 char one_value
[SYSFS_PATH_MAX
];
644 char linebuf
[MAX_LINE_LEN
];
648 len
= sysfs_cpufreq_read_file(cpu
, "stats/time_in_state",
649 linebuf
, sizeof(linebuf
));
655 for (i
= 0; i
< len
; i
++) {
656 if (i
== strlen(linebuf
) || linebuf
[i
] == '\n') {
659 if ((i
- pos
) >= SYSFS_PATH_MAX
)
662 current
->next
= malloc(sizeof(*current
));
665 current
= current
->next
;
667 first
= malloc(sizeof(*first
));
672 current
->first
= first
;
673 current
->next
= NULL
;
675 memcpy(one_value
, linebuf
+ pos
, i
- pos
);
676 one_value
[i
- pos
] = '\0';
677 if (sscanf(one_value
, "%lu %llu",
679 ¤t
->time_in_state
) != 2)
682 *total_time
= *total_time
+ current
->time_in_state
;
691 current
= first
->next
;
698 void cpufreq_put_stats(struct cpufreq_stats
*any
)
700 struct cpufreq_stats
*tmp
, *next
;
713 unsigned long cpufreq_get_transitions(unsigned int cpu
)
715 return sysfs_cpufreq_get_one_value(cpu
, STATS_NUM_TRANSITIONS
);