14f19048fSThomas Gleixner // SPDX-License-Identifier: GPL-2.0-only
27fe2f639SDominik Brodowski /*
37fe2f639SDominik Brodowski * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
47fe2f639SDominik Brodowski */
57fe2f639SDominik Brodowski
67fe2f639SDominik Brodowski
77fe2f639SDominik Brodowski #include <stdio.h>
87fe2f639SDominik Brodowski #include <errno.h>
97fe2f639SDominik Brodowski #include <stdlib.h>
107fe2f639SDominik Brodowski #include <string.h>
11ac5a181dSThomas Renninger #include <sys/types.h>
12ac5a181dSThomas Renninger #include <sys/stat.h>
13ac5a181dSThomas Renninger #include <fcntl.h>
14ac5a181dSThomas Renninger #include <unistd.h>
157fe2f639SDominik Brodowski
167fe2f639SDominik Brodowski #include "cpufreq.h"
17ac5a181dSThomas Renninger #include "cpupower_intern.h"
187fe2f639SDominik Brodowski
19ac5a181dSThomas Renninger /* CPUFREQ sysfs access **************************************************/
20ac5a181dSThomas Renninger
21ac5a181dSThomas Renninger /* helper function to read file from /sys into given buffer */
22ac5a181dSThomas Renninger /* fname is a relative path under "cpuX/cpufreq" dir */
sysfs_cpufreq_read_file(unsigned int cpu,const char * fname,char * buf,size_t buflen)23ac5a181dSThomas Renninger static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname,
24ac5a181dSThomas Renninger char *buf, size_t buflen)
257fe2f639SDominik Brodowski {
26ac5a181dSThomas Renninger char path[SYSFS_PATH_MAX];
27ac5a181dSThomas Renninger
28ac5a181dSThomas Renninger snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
29ac5a181dSThomas Renninger cpu, fname);
309de9aa45SKonstantin Khlebnikov return cpupower_read_sysfs(path, buf, buflen);
317fe2f639SDominik Brodowski }
327fe2f639SDominik Brodowski
33ac5a181dSThomas Renninger /* helper function to write a new value to a /sys file */
34ac5a181dSThomas Renninger /* fname is a relative path under "cpuX/cpufreq" dir */
sysfs_cpufreq_write_file(unsigned int cpu,const char * fname,const char * value,size_t len)35ac5a181dSThomas Renninger static unsigned int sysfs_cpufreq_write_file(unsigned int cpu,
36ac5a181dSThomas Renninger const char *fname,
37ac5a181dSThomas Renninger const char *value, size_t len)
38ac5a181dSThomas Renninger {
39ac5a181dSThomas Renninger char path[SYSFS_PATH_MAX];
40ac5a181dSThomas Renninger int fd;
41ac5a181dSThomas Renninger ssize_t numwrite;
42ac5a181dSThomas Renninger
43ac5a181dSThomas Renninger snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s",
44ac5a181dSThomas Renninger cpu, fname);
45ac5a181dSThomas Renninger
46ac5a181dSThomas Renninger fd = open(path, O_WRONLY);
47ac5a181dSThomas Renninger if (fd == -1)
48ac5a181dSThomas Renninger return 0;
49ac5a181dSThomas Renninger
50ac5a181dSThomas Renninger numwrite = write(fd, value, len);
51ac5a181dSThomas Renninger if (numwrite < 1) {
52ac5a181dSThomas Renninger close(fd);
53ac5a181dSThomas Renninger return 0;
54ac5a181dSThomas Renninger }
55ac5a181dSThomas Renninger
56ac5a181dSThomas Renninger close(fd);
57ac5a181dSThomas Renninger
58ac5a181dSThomas Renninger return (unsigned int) numwrite;
59ac5a181dSThomas Renninger }
60ac5a181dSThomas Renninger
61ac5a181dSThomas Renninger /* read access to files which contain one numeric value */
62ac5a181dSThomas Renninger
63ac5a181dSThomas Renninger enum cpufreq_value {
64ac5a181dSThomas Renninger CPUINFO_CUR_FREQ,
65ac5a181dSThomas Renninger CPUINFO_MIN_FREQ,
66ac5a181dSThomas Renninger CPUINFO_MAX_FREQ,
67ac5a181dSThomas Renninger CPUINFO_LATENCY,
68ac5a181dSThomas Renninger SCALING_CUR_FREQ,
69ac5a181dSThomas Renninger SCALING_MIN_FREQ,
70ac5a181dSThomas Renninger SCALING_MAX_FREQ,
71ac5a181dSThomas Renninger STATS_NUM_TRANSITIONS,
72ac5a181dSThomas Renninger MAX_CPUFREQ_VALUE_READ_FILES
73ac5a181dSThomas Renninger };
74ac5a181dSThomas Renninger
75ac5a181dSThomas Renninger static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = {
76ac5a181dSThomas Renninger [CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq",
77ac5a181dSThomas Renninger [CPUINFO_MIN_FREQ] = "cpuinfo_min_freq",
78ac5a181dSThomas Renninger [CPUINFO_MAX_FREQ] = "cpuinfo_max_freq",
79ac5a181dSThomas Renninger [CPUINFO_LATENCY] = "cpuinfo_transition_latency",
80ac5a181dSThomas Renninger [SCALING_CUR_FREQ] = "scaling_cur_freq",
81ac5a181dSThomas Renninger [SCALING_MIN_FREQ] = "scaling_min_freq",
82ac5a181dSThomas Renninger [SCALING_MAX_FREQ] = "scaling_max_freq",
83ac5a181dSThomas Renninger [STATS_NUM_TRANSITIONS] = "stats/total_trans"
84ac5a181dSThomas Renninger };
85ac5a181dSThomas Renninger
cpufreq_get_sysfs_value_from_table(unsigned int cpu,const char ** table,unsigned int index,unsigned int size)86*e3ede976SHuang Rui unsigned long cpufreq_get_sysfs_value_from_table(unsigned int cpu,
87*e3ede976SHuang Rui const char **table,
88*e3ede976SHuang Rui unsigned int index,
89*e3ede976SHuang Rui unsigned int size)
90ac5a181dSThomas Renninger {
91ac5a181dSThomas Renninger unsigned long value;
92ac5a181dSThomas Renninger unsigned int len;
93ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
94ac5a181dSThomas Renninger char *endp;
95ac5a181dSThomas Renninger
96*e3ede976SHuang Rui if (!table || index >= size || !table[index])
97ac5a181dSThomas Renninger return 0;
98ac5a181dSThomas Renninger
99*e3ede976SHuang Rui len = sysfs_cpufreq_read_file(cpu, table[index], linebuf,
100*e3ede976SHuang Rui sizeof(linebuf));
101ac5a181dSThomas Renninger
102ac5a181dSThomas Renninger if (len == 0)
103ac5a181dSThomas Renninger return 0;
104ac5a181dSThomas Renninger
105ac5a181dSThomas Renninger value = strtoul(linebuf, &endp, 0);
106ac5a181dSThomas Renninger
107ac5a181dSThomas Renninger if (endp == linebuf || errno == ERANGE)
108ac5a181dSThomas Renninger return 0;
109ac5a181dSThomas Renninger
110ac5a181dSThomas Renninger return value;
111ac5a181dSThomas Renninger }
112ac5a181dSThomas Renninger
sysfs_cpufreq_get_one_value(unsigned int cpu,enum cpufreq_value which)113*e3ede976SHuang Rui static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu,
114*e3ede976SHuang Rui enum cpufreq_value which)
115*e3ede976SHuang Rui {
116*e3ede976SHuang Rui return cpufreq_get_sysfs_value_from_table(cpu, cpufreq_value_files,
117*e3ede976SHuang Rui which,
118*e3ede976SHuang Rui MAX_CPUFREQ_VALUE_READ_FILES);
119*e3ede976SHuang Rui }
120*e3ede976SHuang Rui
121ac5a181dSThomas Renninger /* read access to files which contain one string */
122ac5a181dSThomas Renninger
123ac5a181dSThomas Renninger enum cpufreq_string {
124ac5a181dSThomas Renninger SCALING_DRIVER,
125ac5a181dSThomas Renninger SCALING_GOVERNOR,
126ac5a181dSThomas Renninger MAX_CPUFREQ_STRING_FILES
127ac5a181dSThomas Renninger };
128ac5a181dSThomas Renninger
129ac5a181dSThomas Renninger static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = {
130ac5a181dSThomas Renninger [SCALING_DRIVER] = "scaling_driver",
131ac5a181dSThomas Renninger [SCALING_GOVERNOR] = "scaling_governor",
132ac5a181dSThomas Renninger };
133ac5a181dSThomas Renninger
134ac5a181dSThomas Renninger
sysfs_cpufreq_get_one_string(unsigned int cpu,enum cpufreq_string which)135ac5a181dSThomas Renninger static char *sysfs_cpufreq_get_one_string(unsigned int cpu,
136ac5a181dSThomas Renninger enum cpufreq_string which)
137ac5a181dSThomas Renninger {
138ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
139ac5a181dSThomas Renninger char *result;
140ac5a181dSThomas Renninger unsigned int len;
141ac5a181dSThomas Renninger
142ac5a181dSThomas Renninger if (which >= MAX_CPUFREQ_STRING_FILES)
143ac5a181dSThomas Renninger return NULL;
144ac5a181dSThomas Renninger
145ac5a181dSThomas Renninger len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which],
146ac5a181dSThomas Renninger linebuf, sizeof(linebuf));
147ac5a181dSThomas Renninger if (len == 0)
148ac5a181dSThomas Renninger return NULL;
149ac5a181dSThomas Renninger
150ac5a181dSThomas Renninger result = strdup(linebuf);
151ac5a181dSThomas Renninger if (result == NULL)
152ac5a181dSThomas Renninger return NULL;
153ac5a181dSThomas Renninger
154ac5a181dSThomas Renninger if (result[strlen(result) - 1] == '\n')
155ac5a181dSThomas Renninger result[strlen(result) - 1] = '\0';
156ac5a181dSThomas Renninger
157ac5a181dSThomas Renninger return result;
158ac5a181dSThomas Renninger }
159ac5a181dSThomas Renninger
160ac5a181dSThomas Renninger /* write access */
161ac5a181dSThomas Renninger
162ac5a181dSThomas Renninger enum cpufreq_write {
163ac5a181dSThomas Renninger WRITE_SCALING_MIN_FREQ,
164ac5a181dSThomas Renninger WRITE_SCALING_MAX_FREQ,
165ac5a181dSThomas Renninger WRITE_SCALING_GOVERNOR,
166ac5a181dSThomas Renninger WRITE_SCALING_SET_SPEED,
167ac5a181dSThomas Renninger MAX_CPUFREQ_WRITE_FILES
168ac5a181dSThomas Renninger };
169ac5a181dSThomas Renninger
170ac5a181dSThomas Renninger static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = {
171ac5a181dSThomas Renninger [WRITE_SCALING_MIN_FREQ] = "scaling_min_freq",
172ac5a181dSThomas Renninger [WRITE_SCALING_MAX_FREQ] = "scaling_max_freq",
173ac5a181dSThomas Renninger [WRITE_SCALING_GOVERNOR] = "scaling_governor",
174ac5a181dSThomas Renninger [WRITE_SCALING_SET_SPEED] = "scaling_setspeed",
175ac5a181dSThomas Renninger };
176ac5a181dSThomas Renninger
sysfs_cpufreq_write_one_value(unsigned int cpu,enum cpufreq_write which,const char * new_value,size_t len)177ac5a181dSThomas Renninger static int sysfs_cpufreq_write_one_value(unsigned int cpu,
178ac5a181dSThomas Renninger enum cpufreq_write which,
179ac5a181dSThomas Renninger const char *new_value, size_t len)
180ac5a181dSThomas Renninger {
181ac5a181dSThomas Renninger if (which >= MAX_CPUFREQ_WRITE_FILES)
182ac5a181dSThomas Renninger return 0;
183ac5a181dSThomas Renninger
184ac5a181dSThomas Renninger if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which],
185ac5a181dSThomas Renninger new_value, len) != len)
186ac5a181dSThomas Renninger return -ENODEV;
187ac5a181dSThomas Renninger
188ac5a181dSThomas Renninger return 0;
189ac5a181dSThomas Renninger };
190ac5a181dSThomas Renninger
cpufreq_get_freq_kernel(unsigned int cpu)1917fe2f639SDominik Brodowski unsigned long cpufreq_get_freq_kernel(unsigned int cpu)
1927fe2f639SDominik Brodowski {
193ac5a181dSThomas Renninger return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ);
1947fe2f639SDominik Brodowski }
1957fe2f639SDominik Brodowski
cpufreq_get_freq_hardware(unsigned int cpu)1967fe2f639SDominik Brodowski unsigned long cpufreq_get_freq_hardware(unsigned int cpu)
1977fe2f639SDominik Brodowski {
198ac5a181dSThomas Renninger return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ);
1997fe2f639SDominik Brodowski }
2007fe2f639SDominik Brodowski
cpufreq_get_transition_latency(unsigned int cpu)2017fe2f639SDominik Brodowski unsigned long cpufreq_get_transition_latency(unsigned int cpu)
2027fe2f639SDominik Brodowski {
203ac5a181dSThomas Renninger return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY);
2047fe2f639SDominik Brodowski }
2057fe2f639SDominik Brodowski
cpufreq_get_hardware_limits(unsigned int cpu,unsigned long * min,unsigned long * max)2067fe2f639SDominik Brodowski int cpufreq_get_hardware_limits(unsigned int cpu,
2077fe2f639SDominik Brodowski unsigned long *min,
2087fe2f639SDominik Brodowski unsigned long *max)
2097fe2f639SDominik Brodowski {
2107fe2f639SDominik Brodowski if ((!min) || (!max))
2117fe2f639SDominik Brodowski return -EINVAL;
212ac5a181dSThomas Renninger
213ac5a181dSThomas Renninger *min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ);
214ac5a181dSThomas Renninger if (!*min)
215ac5a181dSThomas Renninger return -ENODEV;
216ac5a181dSThomas Renninger
217ac5a181dSThomas Renninger *max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ);
218ac5a181dSThomas Renninger if (!*max)
219ac5a181dSThomas Renninger return -ENODEV;
220ac5a181dSThomas Renninger
221ac5a181dSThomas Renninger return 0;
2227fe2f639SDominik Brodowski }
2237fe2f639SDominik Brodowski
cpufreq_get_driver(unsigned int cpu)2246c2b8185SDominik Brodowski char *cpufreq_get_driver(unsigned int cpu)
2256c2b8185SDominik Brodowski {
226ac5a181dSThomas Renninger return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER);
2277fe2f639SDominik Brodowski }
2287fe2f639SDominik Brodowski
cpufreq_put_driver(char * ptr)2296c2b8185SDominik Brodowski void cpufreq_put_driver(char *ptr)
2306c2b8185SDominik Brodowski {
2317fe2f639SDominik Brodowski if (!ptr)
2327fe2f639SDominik Brodowski return;
2337fe2f639SDominik Brodowski free(ptr);
2347fe2f639SDominik Brodowski }
2357fe2f639SDominik Brodowski
cpufreq_get_policy(unsigned int cpu)2366c2b8185SDominik Brodowski struct cpufreq_policy *cpufreq_get_policy(unsigned int cpu)
2376c2b8185SDominik Brodowski {
238ac5a181dSThomas Renninger struct cpufreq_policy *policy;
239ac5a181dSThomas Renninger
240ac5a181dSThomas Renninger policy = malloc(sizeof(struct cpufreq_policy));
241ac5a181dSThomas Renninger if (!policy)
242ac5a181dSThomas Renninger return NULL;
243ac5a181dSThomas Renninger
244ac5a181dSThomas Renninger policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR);
245ac5a181dSThomas Renninger if (!policy->governor) {
246ac5a181dSThomas Renninger free(policy);
247ac5a181dSThomas Renninger return NULL;
248ac5a181dSThomas Renninger }
249ac5a181dSThomas Renninger policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
250ac5a181dSThomas Renninger policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ);
251ac5a181dSThomas Renninger if ((!policy->min) || (!policy->max)) {
252ac5a181dSThomas Renninger free(policy->governor);
253ac5a181dSThomas Renninger free(policy);
254ac5a181dSThomas Renninger return NULL;
255ac5a181dSThomas Renninger }
256ac5a181dSThomas Renninger
257ac5a181dSThomas Renninger return policy;
2587fe2f639SDominik Brodowski }
2597fe2f639SDominik Brodowski
cpufreq_put_policy(struct cpufreq_policy * policy)2606c2b8185SDominik Brodowski void cpufreq_put_policy(struct cpufreq_policy *policy)
2616c2b8185SDominik Brodowski {
2627fe2f639SDominik Brodowski if ((!policy) || (!policy->governor))
2637fe2f639SDominik Brodowski return;
2647fe2f639SDominik Brodowski
2657fe2f639SDominik Brodowski free(policy->governor);
2667fe2f639SDominik Brodowski policy->governor = NULL;
2677fe2f639SDominik Brodowski free(policy);
2687fe2f639SDominik Brodowski }
2697fe2f639SDominik Brodowski
cpufreq_get_available_governors(unsigned int cpu)2706c2b8185SDominik Brodowski struct cpufreq_available_governors *cpufreq_get_available_governors(unsigned
2716c2b8185SDominik Brodowski int cpu)
2726c2b8185SDominik Brodowski {
273ac5a181dSThomas Renninger struct cpufreq_available_governors *first = NULL;
274ac5a181dSThomas Renninger struct cpufreq_available_governors *current = NULL;
275ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
276ac5a181dSThomas Renninger unsigned int pos, i;
277ac5a181dSThomas Renninger unsigned int len;
278ac5a181dSThomas Renninger
279ac5a181dSThomas Renninger len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors",
280ac5a181dSThomas Renninger linebuf, sizeof(linebuf));
281ac5a181dSThomas Renninger if (len == 0)
282ac5a181dSThomas Renninger return NULL;
283ac5a181dSThomas Renninger
284ac5a181dSThomas Renninger pos = 0;
285ac5a181dSThomas Renninger for (i = 0; i < len; i++) {
286ac5a181dSThomas Renninger if (linebuf[i] == ' ' || linebuf[i] == '\n') {
287ac5a181dSThomas Renninger if (i - pos < 2)
288ac5a181dSThomas Renninger continue;
289ac5a181dSThomas Renninger if (current) {
290ac5a181dSThomas Renninger current->next = malloc(sizeof(*current));
291ac5a181dSThomas Renninger if (!current->next)
292ac5a181dSThomas Renninger goto error_out;
293ac5a181dSThomas Renninger current = current->next;
294ac5a181dSThomas Renninger } else {
295ac5a181dSThomas Renninger first = malloc(sizeof(*first));
296ac5a181dSThomas Renninger if (!first)
297cbf25270SShuah Khan return NULL;
298ac5a181dSThomas Renninger current = first;
299ac5a181dSThomas Renninger }
300ac5a181dSThomas Renninger current->first = first;
301ac5a181dSThomas Renninger current->next = NULL;
302ac5a181dSThomas Renninger
303ac5a181dSThomas Renninger current->governor = malloc(i - pos + 1);
304ac5a181dSThomas Renninger if (!current->governor)
305ac5a181dSThomas Renninger goto error_out;
306ac5a181dSThomas Renninger
307ac5a181dSThomas Renninger memcpy(current->governor, linebuf + pos, i - pos);
308ac5a181dSThomas Renninger current->governor[i - pos] = '\0';
309ac5a181dSThomas Renninger pos = i + 1;
310ac5a181dSThomas Renninger }
311ac5a181dSThomas Renninger }
312ac5a181dSThomas Renninger
313ac5a181dSThomas Renninger return first;
314ac5a181dSThomas Renninger
315ac5a181dSThomas Renninger error_out:
316ac5a181dSThomas Renninger while (first) {
317ac5a181dSThomas Renninger current = first->next;
318ac5a181dSThomas Renninger if (first->governor)
319ac5a181dSThomas Renninger free(first->governor);
320ac5a181dSThomas Renninger free(first);
321ac5a181dSThomas Renninger first = current;
322ac5a181dSThomas Renninger }
323ac5a181dSThomas Renninger return NULL;
3247fe2f639SDominik Brodowski }
3257fe2f639SDominik Brodowski
cpufreq_put_available_governors(struct cpufreq_available_governors * any)3266c2b8185SDominik Brodowski void cpufreq_put_available_governors(struct cpufreq_available_governors *any)
3276c2b8185SDominik Brodowski {
3287fe2f639SDominik Brodowski struct cpufreq_available_governors *tmp, *next;
3297fe2f639SDominik Brodowski
3307fe2f639SDominik Brodowski if (!any)
3317fe2f639SDominik Brodowski return;
3327fe2f639SDominik Brodowski
3337fe2f639SDominik Brodowski tmp = any->first;
3347fe2f639SDominik Brodowski while (tmp) {
3357fe2f639SDominik Brodowski next = tmp->next;
3367fe2f639SDominik Brodowski if (tmp->governor)
3377fe2f639SDominik Brodowski free(tmp->governor);
3387fe2f639SDominik Brodowski free(tmp);
3397fe2f639SDominik Brodowski tmp = next;
3407fe2f639SDominik Brodowski }
3417fe2f639SDominik Brodowski }
3427fe2f639SDominik Brodowski
3437fe2f639SDominik Brodowski
34441ddb7e1SThomas Renninger struct cpufreq_available_frequencies
cpufreq_get_available_frequencies(unsigned int cpu)34541ddb7e1SThomas Renninger *cpufreq_get_available_frequencies(unsigned int cpu)
3466c2b8185SDominik Brodowski {
34741ddb7e1SThomas Renninger struct cpufreq_available_frequencies *first = NULL;
34841ddb7e1SThomas Renninger struct cpufreq_available_frequencies *current = NULL;
349ac5a181dSThomas Renninger char one_value[SYSFS_PATH_MAX];
350ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
351ac5a181dSThomas Renninger unsigned int pos, i;
352ac5a181dSThomas Renninger unsigned int len;
353ac5a181dSThomas Renninger
35441ddb7e1SThomas Renninger len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies",
355ac5a181dSThomas Renninger linebuf, sizeof(linebuf));
356ac5a181dSThomas Renninger if (len == 0)
357ac5a181dSThomas Renninger return NULL;
358ac5a181dSThomas Renninger
359ac5a181dSThomas Renninger pos = 0;
360ac5a181dSThomas Renninger for (i = 0; i < len; i++) {
361ac5a181dSThomas Renninger if (linebuf[i] == ' ' || linebuf[i] == '\n') {
362ac5a181dSThomas Renninger if (i - pos < 2)
363ac5a181dSThomas Renninger continue;
364ac5a181dSThomas Renninger if (i - pos >= SYSFS_PATH_MAX)
365ac5a181dSThomas Renninger goto error_out;
366ac5a181dSThomas Renninger if (current) {
367ac5a181dSThomas Renninger current->next = malloc(sizeof(*current));
368ac5a181dSThomas Renninger if (!current->next)
369ac5a181dSThomas Renninger goto error_out;
370ac5a181dSThomas Renninger current = current->next;
371ac5a181dSThomas Renninger } else {
372ac5a181dSThomas Renninger first = malloc(sizeof(*first));
373ac5a181dSThomas Renninger if (!first)
374cbf25270SShuah Khan return NULL;
375ac5a181dSThomas Renninger current = first;
376ac5a181dSThomas Renninger }
377ac5a181dSThomas Renninger current->first = first;
378ac5a181dSThomas Renninger current->next = NULL;
379ac5a181dSThomas Renninger
380ac5a181dSThomas Renninger memcpy(one_value, linebuf + pos, i - pos);
381ac5a181dSThomas Renninger one_value[i - pos] = '\0';
382ac5a181dSThomas Renninger if (sscanf(one_value, "%lu", ¤t->frequency) != 1)
383ac5a181dSThomas Renninger goto error_out;
384ac5a181dSThomas Renninger
385ac5a181dSThomas Renninger pos = i + 1;
386ac5a181dSThomas Renninger }
387ac5a181dSThomas Renninger }
388ac5a181dSThomas Renninger
389ac5a181dSThomas Renninger return first;
390ac5a181dSThomas Renninger
391ac5a181dSThomas Renninger error_out:
392ac5a181dSThomas Renninger while (first) {
393ac5a181dSThomas Renninger current = first->next;
394ac5a181dSThomas Renninger free(first);
395ac5a181dSThomas Renninger first = current;
396ac5a181dSThomas Renninger }
397ac5a181dSThomas Renninger return NULL;
3987fe2f639SDominik Brodowski }
3997fe2f639SDominik Brodowski
40041ddb7e1SThomas Renninger struct cpufreq_available_frequencies
cpufreq_get_boost_frequencies(unsigned int cpu)40141ddb7e1SThomas Renninger *cpufreq_get_boost_frequencies(unsigned int cpu)
402ae291709SAbhishek Goel {
40341ddb7e1SThomas Renninger struct cpufreq_available_frequencies *first = NULL;
40441ddb7e1SThomas Renninger struct cpufreq_available_frequencies *current = NULL;
40541ddb7e1SThomas Renninger char one_value[SYSFS_PATH_MAX];
40641ddb7e1SThomas Renninger char linebuf[MAX_LINE_LEN];
40741ddb7e1SThomas Renninger unsigned int pos, i;
40841ddb7e1SThomas Renninger unsigned int len;
40941ddb7e1SThomas Renninger
41041ddb7e1SThomas Renninger len = sysfs_cpufreq_read_file(cpu, "scaling_boost_frequencies",
41141ddb7e1SThomas Renninger linebuf, sizeof(linebuf));
41241ddb7e1SThomas Renninger if (len == 0)
41341ddb7e1SThomas Renninger return NULL;
41441ddb7e1SThomas Renninger
41541ddb7e1SThomas Renninger pos = 0;
41641ddb7e1SThomas Renninger for (i = 0; i < len; i++) {
41741ddb7e1SThomas Renninger if (linebuf[i] == ' ' || linebuf[i] == '\n') {
41841ddb7e1SThomas Renninger if (i - pos < 2)
41941ddb7e1SThomas Renninger continue;
42041ddb7e1SThomas Renninger if (i - pos >= SYSFS_PATH_MAX)
42141ddb7e1SThomas Renninger goto error_out;
42241ddb7e1SThomas Renninger if (current) {
42341ddb7e1SThomas Renninger current->next = malloc(sizeof(*current));
42441ddb7e1SThomas Renninger if (!current->next)
42541ddb7e1SThomas Renninger goto error_out;
42641ddb7e1SThomas Renninger current = current->next;
42741ddb7e1SThomas Renninger } else {
42841ddb7e1SThomas Renninger first = malloc(sizeof(*first));
42941ddb7e1SThomas Renninger if (!first)
430cbf25270SShuah Khan return NULL;
43141ddb7e1SThomas Renninger current = first;
43241ddb7e1SThomas Renninger }
43341ddb7e1SThomas Renninger current->first = first;
43441ddb7e1SThomas Renninger current->next = NULL;
43541ddb7e1SThomas Renninger
43641ddb7e1SThomas Renninger memcpy(one_value, linebuf + pos, i - pos);
43741ddb7e1SThomas Renninger one_value[i - pos] = '\0';
43841ddb7e1SThomas Renninger if (sscanf(one_value, "%lu", ¤t->frequency) != 1)
43941ddb7e1SThomas Renninger goto error_out;
44041ddb7e1SThomas Renninger
44141ddb7e1SThomas Renninger pos = i + 1;
44241ddb7e1SThomas Renninger }
44341ddb7e1SThomas Renninger }
44441ddb7e1SThomas Renninger
44541ddb7e1SThomas Renninger return first;
44641ddb7e1SThomas Renninger
44741ddb7e1SThomas Renninger error_out:
44841ddb7e1SThomas Renninger while (first) {
44941ddb7e1SThomas Renninger current = first->next;
45041ddb7e1SThomas Renninger free(first);
45141ddb7e1SThomas Renninger first = current;
45241ddb7e1SThomas Renninger }
45341ddb7e1SThomas Renninger return NULL;
45441ddb7e1SThomas Renninger }
45541ddb7e1SThomas Renninger
cpufreq_put_available_frequencies(struct cpufreq_available_frequencies * any)45641ddb7e1SThomas Renninger void cpufreq_put_available_frequencies(struct cpufreq_available_frequencies *any)
45741ddb7e1SThomas Renninger {
45841ddb7e1SThomas Renninger struct cpufreq_available_frequencies *tmp, *next;
4597fe2f639SDominik Brodowski
4607fe2f639SDominik Brodowski if (!any)
4617fe2f639SDominik Brodowski return;
4627fe2f639SDominik Brodowski
4637fe2f639SDominik Brodowski tmp = any->first;
4647fe2f639SDominik Brodowski while (tmp) {
4657fe2f639SDominik Brodowski next = tmp->next;
4667fe2f639SDominik Brodowski free(tmp);
4677fe2f639SDominik Brodowski tmp = next;
4687fe2f639SDominik Brodowski }
4697fe2f639SDominik Brodowski }
4707fe2f639SDominik Brodowski
cpufreq_put_boost_frequencies(struct cpufreq_available_frequencies * any)47141ddb7e1SThomas Renninger void cpufreq_put_boost_frequencies(struct cpufreq_available_frequencies *any)
47241ddb7e1SThomas Renninger {
47341ddb7e1SThomas Renninger cpufreq_put_available_frequencies(any);
47441ddb7e1SThomas Renninger }
47541ddb7e1SThomas Renninger
sysfs_get_cpu_list(unsigned int cpu,const char * file)476ac5a181dSThomas Renninger static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu,
477ac5a181dSThomas Renninger const char *file)
478ac5a181dSThomas Renninger {
479ac5a181dSThomas Renninger struct cpufreq_affected_cpus *first = NULL;
480ac5a181dSThomas Renninger struct cpufreq_affected_cpus *current = NULL;
481ac5a181dSThomas Renninger char one_value[SYSFS_PATH_MAX];
482ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
483ac5a181dSThomas Renninger unsigned int pos, i;
484ac5a181dSThomas Renninger unsigned int len;
485ac5a181dSThomas Renninger
486ac5a181dSThomas Renninger len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf));
487ac5a181dSThomas Renninger if (len == 0)
488ac5a181dSThomas Renninger return NULL;
489ac5a181dSThomas Renninger
490ac5a181dSThomas Renninger pos = 0;
491ac5a181dSThomas Renninger for (i = 0; i < len; i++) {
492ac5a181dSThomas Renninger if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') {
493ac5a181dSThomas Renninger if (i - pos < 1)
494ac5a181dSThomas Renninger continue;
495ac5a181dSThomas Renninger if (i - pos >= SYSFS_PATH_MAX)
496ac5a181dSThomas Renninger goto error_out;
497ac5a181dSThomas Renninger if (current) {
498ac5a181dSThomas Renninger current->next = malloc(sizeof(*current));
499ac5a181dSThomas Renninger if (!current->next)
500ac5a181dSThomas Renninger goto error_out;
501ac5a181dSThomas Renninger current = current->next;
502ac5a181dSThomas Renninger } else {
503ac5a181dSThomas Renninger first = malloc(sizeof(*first));
504ac5a181dSThomas Renninger if (!first)
505cbf25270SShuah Khan return NULL;
506ac5a181dSThomas Renninger current = first;
507ac5a181dSThomas Renninger }
508ac5a181dSThomas Renninger current->first = first;
509ac5a181dSThomas Renninger current->next = NULL;
510ac5a181dSThomas Renninger
511ac5a181dSThomas Renninger memcpy(one_value, linebuf + pos, i - pos);
512ac5a181dSThomas Renninger one_value[i - pos] = '\0';
513ac5a181dSThomas Renninger
514ac5a181dSThomas Renninger if (sscanf(one_value, "%u", ¤t->cpu) != 1)
515ac5a181dSThomas Renninger goto error_out;
516ac5a181dSThomas Renninger
517ac5a181dSThomas Renninger pos = i + 1;
518ac5a181dSThomas Renninger }
519ac5a181dSThomas Renninger }
520ac5a181dSThomas Renninger
521ac5a181dSThomas Renninger return first;
522ac5a181dSThomas Renninger
523ac5a181dSThomas Renninger error_out:
524ac5a181dSThomas Renninger while (first) {
525ac5a181dSThomas Renninger current = first->next;
526ac5a181dSThomas Renninger free(first);
527ac5a181dSThomas Renninger first = current;
528ac5a181dSThomas Renninger }
529ac5a181dSThomas Renninger return NULL;
530ac5a181dSThomas Renninger }
5317fe2f639SDominik Brodowski
cpufreq_get_affected_cpus(unsigned int cpu)5326c2b8185SDominik Brodowski struct cpufreq_affected_cpus *cpufreq_get_affected_cpus(unsigned int cpu)
5336c2b8185SDominik Brodowski {
534ac5a181dSThomas Renninger return sysfs_get_cpu_list(cpu, "affected_cpus");
5357fe2f639SDominik Brodowski }
5367fe2f639SDominik Brodowski
cpufreq_put_affected_cpus(struct cpufreq_affected_cpus * any)5376c2b8185SDominik Brodowski void cpufreq_put_affected_cpus(struct cpufreq_affected_cpus *any)
5386c2b8185SDominik Brodowski {
5397fe2f639SDominik Brodowski struct cpufreq_affected_cpus *tmp, *next;
5407fe2f639SDominik Brodowski
5417fe2f639SDominik Brodowski if (!any)
5427fe2f639SDominik Brodowski return;
5437fe2f639SDominik Brodowski
5447fe2f639SDominik Brodowski tmp = any->first;
5457fe2f639SDominik Brodowski while (tmp) {
5467fe2f639SDominik Brodowski next = tmp->next;
5477fe2f639SDominik Brodowski free(tmp);
5487fe2f639SDominik Brodowski tmp = next;
5497fe2f639SDominik Brodowski }
5507fe2f639SDominik Brodowski }
5517fe2f639SDominik Brodowski
5527fe2f639SDominik Brodowski
cpufreq_get_related_cpus(unsigned int cpu)5536c2b8185SDominik Brodowski struct cpufreq_affected_cpus *cpufreq_get_related_cpus(unsigned int cpu)
5546c2b8185SDominik Brodowski {
555ac5a181dSThomas Renninger return sysfs_get_cpu_list(cpu, "related_cpus");
5567fe2f639SDominik Brodowski }
5577fe2f639SDominik Brodowski
cpufreq_put_related_cpus(struct cpufreq_affected_cpus * any)5586c2b8185SDominik Brodowski void cpufreq_put_related_cpus(struct cpufreq_affected_cpus *any)
5596c2b8185SDominik Brodowski {
5607fe2f639SDominik Brodowski cpufreq_put_affected_cpus(any);
5617fe2f639SDominik Brodowski }
5627fe2f639SDominik Brodowski
verify_gov(char * new_gov,char * passed_gov)563ac5a181dSThomas Renninger static int verify_gov(char *new_gov, char *passed_gov)
564ac5a181dSThomas Renninger {
565ac5a181dSThomas Renninger unsigned int i, j = 0;
566ac5a181dSThomas Renninger
567ac5a181dSThomas Renninger if (!passed_gov || (strlen(passed_gov) > 19))
568ac5a181dSThomas Renninger return -EINVAL;
569ac5a181dSThomas Renninger
570ac5a181dSThomas Renninger strncpy(new_gov, passed_gov, 20);
571ac5a181dSThomas Renninger for (i = 0; i < 20; i++) {
572ac5a181dSThomas Renninger if (j) {
573ac5a181dSThomas Renninger new_gov[i] = '\0';
574ac5a181dSThomas Renninger continue;
575ac5a181dSThomas Renninger }
576ac5a181dSThomas Renninger if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z'))
577ac5a181dSThomas Renninger continue;
578ac5a181dSThomas Renninger
579ac5a181dSThomas Renninger if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z'))
580ac5a181dSThomas Renninger continue;
581ac5a181dSThomas Renninger
582ac5a181dSThomas Renninger if (new_gov[i] == '-')
583ac5a181dSThomas Renninger continue;
584ac5a181dSThomas Renninger
585ac5a181dSThomas Renninger if (new_gov[i] == '_')
586ac5a181dSThomas Renninger continue;
587ac5a181dSThomas Renninger
588ac5a181dSThomas Renninger if (new_gov[i] == '\0') {
589ac5a181dSThomas Renninger j = 1;
590ac5a181dSThomas Renninger continue;
591ac5a181dSThomas Renninger }
592ac5a181dSThomas Renninger return -EINVAL;
593ac5a181dSThomas Renninger }
594ac5a181dSThomas Renninger new_gov[19] = '\0';
595ac5a181dSThomas Renninger return 0;
596ac5a181dSThomas Renninger }
5977fe2f639SDominik Brodowski
cpufreq_set_policy(unsigned int cpu,struct cpufreq_policy * policy)5986c2b8185SDominik Brodowski int cpufreq_set_policy(unsigned int cpu, struct cpufreq_policy *policy)
5996c2b8185SDominik Brodowski {
600ac5a181dSThomas Renninger char min[SYSFS_PATH_MAX];
601ac5a181dSThomas Renninger char max[SYSFS_PATH_MAX];
602ac5a181dSThomas Renninger char gov[SYSFS_PATH_MAX];
603ac5a181dSThomas Renninger int ret;
604ac5a181dSThomas Renninger unsigned long old_min;
605ac5a181dSThomas Renninger int write_max_first;
606ac5a181dSThomas Renninger
6077fe2f639SDominik Brodowski if (!policy || !(policy->governor))
6087fe2f639SDominik Brodowski return -EINVAL;
6097fe2f639SDominik Brodowski
610ac5a181dSThomas Renninger if (policy->max < policy->min)
611ac5a181dSThomas Renninger return -EINVAL;
612ac5a181dSThomas Renninger
613ac5a181dSThomas Renninger if (verify_gov(gov, policy->governor))
614ac5a181dSThomas Renninger return -EINVAL;
615ac5a181dSThomas Renninger
616ac5a181dSThomas Renninger snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min);
617ac5a181dSThomas Renninger snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max);
618ac5a181dSThomas Renninger
619ac5a181dSThomas Renninger old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ);
620ac5a181dSThomas Renninger write_max_first = (old_min && (policy->max < old_min) ? 0 : 1);
621ac5a181dSThomas Renninger
622ac5a181dSThomas Renninger if (write_max_first) {
623ac5a181dSThomas Renninger ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
624ac5a181dSThomas Renninger max, strlen(max));
625ac5a181dSThomas Renninger if (ret)
626ac5a181dSThomas Renninger return ret;
627ac5a181dSThomas Renninger }
628ac5a181dSThomas Renninger
629ac5a181dSThomas Renninger ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min,
630ac5a181dSThomas Renninger strlen(min));
631ac5a181dSThomas Renninger if (ret)
632ac5a181dSThomas Renninger return ret;
633ac5a181dSThomas Renninger
634ac5a181dSThomas Renninger if (!write_max_first) {
635ac5a181dSThomas Renninger ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
636ac5a181dSThomas Renninger max, strlen(max));
637ac5a181dSThomas Renninger if (ret)
638ac5a181dSThomas Renninger return ret;
639ac5a181dSThomas Renninger }
640ac5a181dSThomas Renninger
641ac5a181dSThomas Renninger return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
642ac5a181dSThomas Renninger gov, strlen(gov));
6437fe2f639SDominik Brodowski }
6447fe2f639SDominik Brodowski
6457fe2f639SDominik Brodowski
cpufreq_modify_policy_min(unsigned int cpu,unsigned long min_freq)6466c2b8185SDominik Brodowski int cpufreq_modify_policy_min(unsigned int cpu, unsigned long min_freq)
6476c2b8185SDominik Brodowski {
648ac5a181dSThomas Renninger char value[SYSFS_PATH_MAX];
649ac5a181dSThomas Renninger
650ac5a181dSThomas Renninger snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq);
651ac5a181dSThomas Renninger
652ac5a181dSThomas Renninger return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ,
653ac5a181dSThomas Renninger value, strlen(value));
6547fe2f639SDominik Brodowski }
6557fe2f639SDominik Brodowski
6567fe2f639SDominik Brodowski
cpufreq_modify_policy_max(unsigned int cpu,unsigned long max_freq)6576c2b8185SDominik Brodowski int cpufreq_modify_policy_max(unsigned int cpu, unsigned long max_freq)
6586c2b8185SDominik Brodowski {
659ac5a181dSThomas Renninger char value[SYSFS_PATH_MAX];
6607fe2f639SDominik Brodowski
661ac5a181dSThomas Renninger snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq);
662ac5a181dSThomas Renninger
663ac5a181dSThomas Renninger return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ,
664ac5a181dSThomas Renninger value, strlen(value));
665ac5a181dSThomas Renninger }
6667fe2f639SDominik Brodowski
cpufreq_modify_policy_governor(unsigned int cpu,char * governor)6676c2b8185SDominik Brodowski int cpufreq_modify_policy_governor(unsigned int cpu, char *governor)
6686c2b8185SDominik Brodowski {
669ac5a181dSThomas Renninger char new_gov[SYSFS_PATH_MAX];
670ac5a181dSThomas Renninger
6717fe2f639SDominik Brodowski if ((!governor) || (strlen(governor) > 19))
6727fe2f639SDominik Brodowski return -EINVAL;
6737fe2f639SDominik Brodowski
674ac5a181dSThomas Renninger if (verify_gov(new_gov, governor))
675ac5a181dSThomas Renninger return -EINVAL;
676ac5a181dSThomas Renninger
677ac5a181dSThomas Renninger return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR,
678ac5a181dSThomas Renninger new_gov, strlen(new_gov));
6797fe2f639SDominik Brodowski }
6807fe2f639SDominik Brodowski
cpufreq_set_frequency(unsigned int cpu,unsigned long target_frequency)6816c2b8185SDominik Brodowski int cpufreq_set_frequency(unsigned int cpu, unsigned long target_frequency)
6826c2b8185SDominik Brodowski {
683ac5a181dSThomas Renninger struct cpufreq_policy *pol = cpufreq_get_policy(cpu);
684ac5a181dSThomas Renninger char userspace_gov[] = "userspace";
685ac5a181dSThomas Renninger char freq[SYSFS_PATH_MAX];
686ac5a181dSThomas Renninger int ret;
687ac5a181dSThomas Renninger
688ac5a181dSThomas Renninger if (!pol)
689ac5a181dSThomas Renninger return -ENODEV;
690ac5a181dSThomas Renninger
691ac5a181dSThomas Renninger if (strncmp(pol->governor, userspace_gov, 9) != 0) {
692ac5a181dSThomas Renninger ret = cpufreq_modify_policy_governor(cpu, userspace_gov);
693ac5a181dSThomas Renninger if (ret) {
694ac5a181dSThomas Renninger cpufreq_put_policy(pol);
695ac5a181dSThomas Renninger return ret;
696ac5a181dSThomas Renninger }
697ac5a181dSThomas Renninger }
698ac5a181dSThomas Renninger
699ac5a181dSThomas Renninger cpufreq_put_policy(pol);
700ac5a181dSThomas Renninger
701ac5a181dSThomas Renninger snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency);
702ac5a181dSThomas Renninger
703ac5a181dSThomas Renninger return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED,
704ac5a181dSThomas Renninger freq, strlen(freq));
7057fe2f639SDominik Brodowski }
7067fe2f639SDominik Brodowski
cpufreq_get_stats(unsigned int cpu,unsigned long long * total_time)7076c2b8185SDominik Brodowski struct cpufreq_stats *cpufreq_get_stats(unsigned int cpu,
7086c2b8185SDominik Brodowski unsigned long long *total_time)
7096c2b8185SDominik Brodowski {
710ac5a181dSThomas Renninger struct cpufreq_stats *first = NULL;
711ac5a181dSThomas Renninger struct cpufreq_stats *current = NULL;
712ac5a181dSThomas Renninger char one_value[SYSFS_PATH_MAX];
713ac5a181dSThomas Renninger char linebuf[MAX_LINE_LEN];
714ac5a181dSThomas Renninger unsigned int pos, i;
715ac5a181dSThomas Renninger unsigned int len;
716ac5a181dSThomas Renninger
717ac5a181dSThomas Renninger len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state",
718ac5a181dSThomas Renninger linebuf, sizeof(linebuf));
719ac5a181dSThomas Renninger if (len == 0)
720ac5a181dSThomas Renninger return NULL;
721ac5a181dSThomas Renninger
722ac5a181dSThomas Renninger *total_time = 0;
723ac5a181dSThomas Renninger pos = 0;
724ac5a181dSThomas Renninger for (i = 0; i < len; i++) {
725ac5a181dSThomas Renninger if (i == strlen(linebuf) || linebuf[i] == '\n') {
726ac5a181dSThomas Renninger if (i - pos < 2)
727ac5a181dSThomas Renninger continue;
728ac5a181dSThomas Renninger if ((i - pos) >= SYSFS_PATH_MAX)
729ac5a181dSThomas Renninger goto error_out;
730ac5a181dSThomas Renninger if (current) {
731ac5a181dSThomas Renninger current->next = malloc(sizeof(*current));
732ac5a181dSThomas Renninger if (!current->next)
733ac5a181dSThomas Renninger goto error_out;
734ac5a181dSThomas Renninger current = current->next;
735ac5a181dSThomas Renninger } else {
736ac5a181dSThomas Renninger first = malloc(sizeof(*first));
737ac5a181dSThomas Renninger if (!first)
738cbf25270SShuah Khan return NULL;
739ac5a181dSThomas Renninger current = first;
740ac5a181dSThomas Renninger }
741ac5a181dSThomas Renninger current->first = first;
742ac5a181dSThomas Renninger current->next = NULL;
743ac5a181dSThomas Renninger
744ac5a181dSThomas Renninger memcpy(one_value, linebuf + pos, i - pos);
745ac5a181dSThomas Renninger one_value[i - pos] = '\0';
746ac5a181dSThomas Renninger if (sscanf(one_value, "%lu %llu",
747ac5a181dSThomas Renninger ¤t->frequency,
748ac5a181dSThomas Renninger ¤t->time_in_state) != 2)
749ac5a181dSThomas Renninger goto error_out;
750ac5a181dSThomas Renninger
751ac5a181dSThomas Renninger *total_time = *total_time + current->time_in_state;
752ac5a181dSThomas Renninger pos = i + 1;
753ac5a181dSThomas Renninger }
754ac5a181dSThomas Renninger }
755ac5a181dSThomas Renninger
756ac5a181dSThomas Renninger return first;
757ac5a181dSThomas Renninger
758ac5a181dSThomas Renninger error_out:
759ac5a181dSThomas Renninger while (first) {
760ac5a181dSThomas Renninger current = first->next;
761ac5a181dSThomas Renninger free(first);
762ac5a181dSThomas Renninger first = current;
763ac5a181dSThomas Renninger }
764ac5a181dSThomas Renninger return NULL;
7657fe2f639SDominik Brodowski }
7667fe2f639SDominik Brodowski
cpufreq_put_stats(struct cpufreq_stats * any)7676c2b8185SDominik Brodowski void cpufreq_put_stats(struct cpufreq_stats *any)
7686c2b8185SDominik Brodowski {
7697fe2f639SDominik Brodowski struct cpufreq_stats *tmp, *next;
7707fe2f639SDominik Brodowski
7717fe2f639SDominik Brodowski if (!any)
7727fe2f639SDominik Brodowski return;
7737fe2f639SDominik Brodowski
7747fe2f639SDominik Brodowski tmp = any->first;
7757fe2f639SDominik Brodowski while (tmp) {
7767fe2f639SDominik Brodowski next = tmp->next;
7777fe2f639SDominik Brodowski free(tmp);
7787fe2f639SDominik Brodowski tmp = next;
7797fe2f639SDominik Brodowski }
7807fe2f639SDominik Brodowski }
7817fe2f639SDominik Brodowski
cpufreq_get_transitions(unsigned int cpu)7826c2b8185SDominik Brodowski unsigned long cpufreq_get_transitions(unsigned int cpu)
7836c2b8185SDominik Brodowski {
784ac5a181dSThomas Renninger return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS);
7857fe2f639SDominik Brodowski }
786