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