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