| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | /*
 | 
					
						
							|  |  |  |  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de> | 
					
						
							|  |  |  |  * | 
					
						
							|  |  |  |  *  Licensed under the terms of the GNU GPL License version 2. | 
					
						
							|  |  |  |  */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include <stdio.h>
 | 
					
						
							|  |  |  | #include <errno.h>
 | 
					
						
							|  |  |  | #include <stdlib.h>
 | 
					
						
							|  |  |  | #include <string.h>
 | 
					
						
							|  |  |  | #include <limits.h>
 | 
					
						
							|  |  |  | #include <sys/types.h>
 | 
					
						
							|  |  |  | #include <sys/stat.h>
 | 
					
						
							|  |  |  | #include <fcntl.h>
 | 
					
						
							|  |  |  | #include <unistd.h>
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #include "cpufreq.h"
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | #define PATH_TO_CPU "/sys/devices/system/cpu/"
 | 
					
						
							| 
									
										
										
										
											2011-04-25 21:34:23 +04:00
										 |  |  | #define MAX_LINE_LEN 4096
 | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | #define SYSFS_PATH_MAX 255
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	int fd; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	ssize_t numread; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	fd = open(path, O_RDONLY); | 
					
						
							|  |  |  | 	if (fd == -1) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	numread = read(fd, buf, buflen - 1); | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (numread < 1) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		close(fd); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	buf[numread] = '\0'; | 
					
						
							|  |  |  | 	close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	return (unsigned int) numread; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CPUFREQ sysfs access **************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* helper function to read file from /sys into given buffer */ | 
					
						
							|  |  |  | /* fname is a relative path under "cpuX/cpufreq" dir */ | 
					
						
							|  |  |  | static unsigned int sysfs_cpufreq_read_file(unsigned int cpu, const char *fname, | 
					
						
							|  |  |  | 					    char *buf, size_t buflen) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char path[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | 
					
						
							|  |  |  | 			 cpu, fname); | 
					
						
							|  |  |  | 	return sysfs_read_file(path, buf, buflen); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* helper function to write a new value to a /sys file */ | 
					
						
							|  |  |  | /* fname is a relative path under "cpuX/cpufreq" dir */ | 
					
						
							|  |  |  | static unsigned int sysfs_cpufreq_write_file(unsigned int cpu, | 
					
						
							|  |  |  | 					     const char *fname, | 
					
						
							|  |  |  | 					     const char *value, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char path[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	int fd; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	ssize_t numwrite; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpufreq/%s", | 
					
						
							|  |  |  | 			 cpu, fname); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	fd = open(path, O_WRONLY); | 
					
						
							|  |  |  | 	if (fd == -1) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	numwrite = write(fd, value, len); | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (numwrite < 1) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		close(fd); | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	close(fd); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	return (unsigned int) numwrite; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* read access to files which contain one numeric value */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum cpufreq_value { | 
					
						
							|  |  |  | 	CPUINFO_CUR_FREQ, | 
					
						
							|  |  |  | 	CPUINFO_MIN_FREQ, | 
					
						
							|  |  |  | 	CPUINFO_MAX_FREQ, | 
					
						
							|  |  |  | 	CPUINFO_LATENCY, | 
					
						
							|  |  |  | 	SCALING_CUR_FREQ, | 
					
						
							|  |  |  | 	SCALING_MIN_FREQ, | 
					
						
							|  |  |  | 	SCALING_MAX_FREQ, | 
					
						
							|  |  |  | 	STATS_NUM_TRANSITIONS, | 
					
						
							|  |  |  | 	MAX_CPUFREQ_VALUE_READ_FILES | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *cpufreq_value_files[MAX_CPUFREQ_VALUE_READ_FILES] = { | 
					
						
							|  |  |  | 	[CPUINFO_CUR_FREQ] = "cpuinfo_cur_freq", | 
					
						
							|  |  |  | 	[CPUINFO_MIN_FREQ] = "cpuinfo_min_freq", | 
					
						
							|  |  |  | 	[CPUINFO_MAX_FREQ] = "cpuinfo_max_freq", | 
					
						
							|  |  |  | 	[CPUINFO_LATENCY]  = "cpuinfo_transition_latency", | 
					
						
							|  |  |  | 	[SCALING_CUR_FREQ] = "scaling_cur_freq", | 
					
						
							|  |  |  | 	[SCALING_MIN_FREQ] = "scaling_min_freq", | 
					
						
							|  |  |  | 	[SCALING_MAX_FREQ] = "scaling_max_freq", | 
					
						
							|  |  |  | 	[STATS_NUM_TRANSITIONS] = "stats/total_trans" | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static unsigned long sysfs_cpufreq_get_one_value(unsigned int cpu, | 
					
						
							|  |  |  | 						 enum cpufreq_value which) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	unsigned long value; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	char *endp; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (which >= MAX_CPUFREQ_VALUE_READ_FILES) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, cpufreq_value_files[which], | 
					
						
							|  |  |  | 				linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	value = strtoul(linebuf, &endp, 0); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (endp == linebuf || errno == ERANGE) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return value; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* read access to files which contain one string */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum cpufreq_string { | 
					
						
							|  |  |  | 	SCALING_DRIVER, | 
					
						
							|  |  |  | 	SCALING_GOVERNOR, | 
					
						
							|  |  |  | 	MAX_CPUFREQ_STRING_FILES | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *cpufreq_string_files[MAX_CPUFREQ_STRING_FILES] = { | 
					
						
							|  |  |  | 	[SCALING_DRIVER] = "scaling_driver", | 
					
						
							|  |  |  | 	[SCALING_GOVERNOR] = "scaling_governor", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | static char *sysfs_cpufreq_get_one_string(unsigned int cpu, | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					   enum cpufreq_string which) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	char *result; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (which >= MAX_CPUFREQ_STRING_FILES) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, cpufreq_string_files[which], | 
					
						
							|  |  |  | 				linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	result = strdup(linebuf); | 
					
						
							|  |  |  | 	if (result == NULL) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (result[strlen(result) - 1] == '\n') | 
					
						
							|  |  |  | 		result[strlen(result) - 1] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return result; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* write access */ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | enum cpufreq_write { | 
					
						
							|  |  |  | 	WRITE_SCALING_MIN_FREQ, | 
					
						
							|  |  |  | 	WRITE_SCALING_MAX_FREQ, | 
					
						
							|  |  |  | 	WRITE_SCALING_GOVERNOR, | 
					
						
							|  |  |  | 	WRITE_SCALING_SET_SPEED, | 
					
						
							|  |  |  | 	MAX_CPUFREQ_WRITE_FILES | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static const char *cpufreq_write_files[MAX_CPUFREQ_WRITE_FILES] = { | 
					
						
							|  |  |  | 	[WRITE_SCALING_MIN_FREQ] = "scaling_min_freq", | 
					
						
							|  |  |  | 	[WRITE_SCALING_MAX_FREQ] = "scaling_max_freq", | 
					
						
							|  |  |  | 	[WRITE_SCALING_GOVERNOR] = "scaling_governor", | 
					
						
							|  |  |  | 	[WRITE_SCALING_SET_SPEED] = "scaling_setspeed", | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int sysfs_cpufreq_write_one_value(unsigned int cpu, | 
					
						
							|  |  |  | 					 enum cpufreq_write which, | 
					
						
							|  |  |  | 					 const char *new_value, size_t len) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if (which >= MAX_CPUFREQ_WRITE_FILES) | 
					
						
							|  |  |  | 		return 0; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (sysfs_cpufreq_write_file(cpu, cpufreq_write_files[which], | 
					
						
							|  |  |  | 					new_value, len) != len) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long sysfs_get_freq_kernel(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sysfs_cpufreq_get_one_value(cpu, SCALING_CUR_FREQ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long sysfs_get_freq_hardware(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sysfs_cpufreq_get_one_value(cpu, CPUINFO_CUR_FREQ); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long sysfs_get_freq_transition_latency(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sysfs_cpufreq_get_one_value(cpu, CPUINFO_LATENCY); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int sysfs_get_freq_hardware_limits(unsigned int cpu, | 
					
						
							|  |  |  | 			      unsigned long *min, | 
					
						
							|  |  |  | 			      unsigned long *max) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	if ((!min) || (!max)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*min = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MIN_FREQ); | 
					
						
							|  |  |  | 	if (!*min) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*max = sysfs_cpufreq_get_one_value(cpu, CPUINFO_MAX_FREQ); | 
					
						
							|  |  |  | 	if (!*max) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | char *sysfs_get_freq_driver(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	return sysfs_cpufreq_get_one_string(cpu, SCALING_DRIVER); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | struct cpufreq_policy *sysfs_get_freq_policy(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_policy *policy; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policy = malloc(sizeof(struct cpufreq_policy)); | 
					
						
							|  |  |  | 	if (!policy) | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	policy->governor = sysfs_cpufreq_get_one_string(cpu, SCALING_GOVERNOR); | 
					
						
							|  |  |  | 	if (!policy->governor) { | 
					
						
							|  |  |  | 		free(policy); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	policy->min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | 
					
						
							|  |  |  | 	policy->max = sysfs_cpufreq_get_one_value(cpu, SCALING_MAX_FREQ); | 
					
						
							|  |  |  | 	if ((!policy->min) || (!policy->max)) { | 
					
						
							|  |  |  | 		free(policy->governor); | 
					
						
							|  |  |  | 		free(policy); | 
					
						
							|  |  |  | 		return NULL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return policy; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct cpufreq_available_governors * | 
					
						
							|  |  |  | sysfs_get_freq_available_governors(unsigned int cpu) { | 
					
						
							|  |  |  | 	struct cpufreq_available_governors *first = NULL; | 
					
						
							|  |  |  | 	struct cpufreq_available_governors *current = NULL; | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	unsigned int pos, i; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, "scaling_available_governors", | 
					
						
							|  |  |  | 				linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos = 0; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		if (linebuf[i] == ' ' || linebuf[i] == '\n') { | 
					
						
							|  |  |  | 			if (i - pos < 2) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (current) { | 
					
						
							|  |  |  | 				current->next = malloc(sizeof(*current)); | 
					
						
							|  |  |  | 				if (!current->next) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = current->next; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 				first = malloc(sizeof(*first)); | 
					
						
							|  |  |  | 				if (!first) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = first; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			current->first = first; | 
					
						
							|  |  |  | 			current->next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			current->governor = malloc(i - pos + 1); | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (!current->governor) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			memcpy(current->governor, linebuf + pos, i - pos); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			current->governor[i - pos] = '\0'; | 
					
						
							|  |  |  | 			pos = i + 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  error_out: | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	while (first) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		current = first->next; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 		if (first->governor) | 
					
						
							|  |  |  | 			free(first->governor); | 
					
						
							|  |  |  | 		free(first); | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		first = current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | struct cpufreq_available_frequencies * | 
					
						
							|  |  |  | sysfs_get_available_frequencies(unsigned int cpu) { | 
					
						
							|  |  |  | 	struct cpufreq_available_frequencies *first = NULL; | 
					
						
							|  |  |  | 	struct cpufreq_available_frequencies *current = NULL; | 
					
						
							|  |  |  | 	char one_value[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	unsigned int pos, i; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, "scaling_available_frequencies", | 
					
						
							|  |  |  | 				linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos = 0; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		if (linebuf[i] == ' ' || linebuf[i] == '\n') { | 
					
						
							|  |  |  | 			if (i - pos < 2) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (i - pos >= SYSFS_PATH_MAX) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (current) { | 
					
						
							|  |  |  | 				current->next = malloc(sizeof(*current)); | 
					
						
							|  |  |  | 				if (!current->next) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = current->next; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 				first = malloc(sizeof(*first)); | 
					
						
							|  |  |  | 				if (!first) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = first; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			current->first = first; | 
					
						
							|  |  |  | 			current->next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			memcpy(one_value, linebuf + pos, i - pos); | 
					
						
							|  |  |  | 			one_value[i - pos] = '\0'; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (sscanf(one_value, "%lu", ¤t->frequency) != 1) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			pos = i + 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  error_out: | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	while (first) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		current = first->next; | 
					
						
							|  |  |  | 		free(first); | 
					
						
							|  |  |  | 		first = current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | static struct cpufreq_affected_cpus *sysfs_get_cpu_list(unsigned int cpu, | 
					
						
							|  |  |  | 							const char *file) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_affected_cpus *first = NULL; | 
					
						
							|  |  |  | 	struct cpufreq_affected_cpus *current = NULL; | 
					
						
							|  |  |  | 	char one_value[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	unsigned int pos, i; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, file, linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	pos = 0; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		if (i == len || linebuf[i] == ' ' || linebuf[i] == '\n') { | 
					
						
							|  |  |  | 			if (i - pos  < 1) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (i - pos >= SYSFS_PATH_MAX) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (current) { | 
					
						
							|  |  |  | 				current->next = malloc(sizeof(*current)); | 
					
						
							|  |  |  | 				if (!current->next) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = current->next; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 				first = malloc(sizeof(*first)); | 
					
						
							|  |  |  | 				if (!first) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = first; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			current->first = first; | 
					
						
							|  |  |  | 			current->next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			memcpy(one_value, linebuf + pos, i - pos); | 
					
						
							|  |  |  | 			one_value[i - pos] = '\0'; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (sscanf(one_value, "%u", ¤t->cpu) != 1) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			pos = i + 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  error_out: | 
					
						
							|  |  |  | 	while (first) { | 
					
						
							|  |  |  | 		current = first->next; | 
					
						
							|  |  |  | 		free(first); | 
					
						
							|  |  |  | 		first = current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | struct cpufreq_affected_cpus *sysfs_get_freq_affected_cpus(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	return sysfs_get_cpu_list(cpu, "affected_cpus"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | struct cpufreq_affected_cpus *sysfs_get_freq_related_cpus(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	return sysfs_get_cpu_list(cpu, "related_cpus"); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | struct cpufreq_stats *sysfs_get_freq_stats(unsigned int cpu, | 
					
						
							|  |  |  | 					unsigned long long *total_time) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_stats *first = NULL; | 
					
						
							|  |  |  | 	struct cpufreq_stats *current = NULL; | 
					
						
							|  |  |  | 	char one_value[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	char linebuf[MAX_LINE_LEN]; | 
					
						
							|  |  |  | 	unsigned int pos, i; | 
					
						
							|  |  |  | 	unsigned int len; | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	len = sysfs_cpufreq_read_file(cpu, "stats/time_in_state", | 
					
						
							|  |  |  | 				linebuf, sizeof(linebuf)); | 
					
						
							|  |  |  | 	if (len == 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	*total_time = 0; | 
					
						
							|  |  |  | 	pos = 0; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	for (i = 0; i < len; i++) { | 
					
						
							|  |  |  | 		if (i == strlen(linebuf) || linebuf[i] == '\n')	{ | 
					
						
							|  |  |  | 			if (i - pos < 2) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if ((i - pos) >= SYSFS_PATH_MAX) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (current) { | 
					
						
							|  |  |  | 				current->next = malloc(sizeof(*current)); | 
					
						
							|  |  |  | 				if (!current->next) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = current->next; | 
					
						
							|  |  |  | 			} else { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 				first = malloc(sizeof(*first)); | 
					
						
							|  |  |  | 				if (!first) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 					goto error_out; | 
					
						
							|  |  |  | 				current = first; | 
					
						
							|  |  |  | 			} | 
					
						
							|  |  |  | 			current->first = first; | 
					
						
							|  |  |  | 			current->next = NULL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			memcpy(one_value, linebuf + pos, i - pos); | 
					
						
							|  |  |  | 			one_value[i - pos] = '\0'; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			if (sscanf(one_value, "%lu %llu", | 
					
						
							|  |  |  | 					¤t->frequency, | 
					
						
							|  |  |  | 					¤t->time_in_state) != 2) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 				goto error_out; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 			*total_time = *total_time + current->time_in_state; | 
					
						
							|  |  |  | 			pos = i + 1; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  |  error_out: | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	while (first) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		current = first->next; | 
					
						
							|  |  |  | 		free(first); | 
					
						
							|  |  |  | 		first = current; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	return NULL; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | unsigned long sysfs_get_freq_transitions(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	return sysfs_cpufreq_get_one_value(cpu, STATS_NUM_TRANSITIONS); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | static int verify_gov(char *new_gov, char *passed_gov) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	unsigned int i, j = 0; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 	if (!passed_gov || (strlen(passed_gov) > 19)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	strncpy(new_gov, passed_gov, 20); | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	for (i = 0; i < 20; i++) { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		if (j) { | 
					
						
							|  |  |  | 			new_gov[i] = '\0'; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 		if ((new_gov[i] >= 'a') && (new_gov[i] <= 'z')) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if ((new_gov[i] >= 'A') && (new_gov[i] <= 'Z')) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (new_gov[i] == '-') | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 
 | 
					
						
							|  |  |  | 		if (new_gov[i] == '_') | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 			continue; | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		if (new_gov[i] == '\0') { | 
					
						
							|  |  |  | 			j = 1; | 
					
						
							|  |  |  | 			continue; | 
					
						
							|  |  |  | 		} | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 	new_gov[19] = '\0'; | 
					
						
							|  |  |  | 	return 0; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int sysfs_modify_freq_policy_governor(unsigned int cpu, char *governor) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char new_gov[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!governor) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verify_gov(new_gov, governor)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | 
					
						
							|  |  |  | 					     new_gov, strlen(new_gov)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int sysfs_modify_freq_policy_max(unsigned int cpu, unsigned long max_freq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char value[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(value, SYSFS_PATH_MAX, "%lu", max_freq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | 
					
						
							|  |  |  | 					     value, strlen(value)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int sysfs_modify_freq_policy_min(unsigned int cpu, unsigned long min_freq) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char value[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(value, SYSFS_PATH_MAX, "%lu", min_freq); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, | 
					
						
							|  |  |  | 					     value, strlen(value)); | 
					
						
							|  |  |  | }; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | int sysfs_set_freq_policy(unsigned int cpu, struct cpufreq_policy *policy) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char min[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	char max[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	char gov[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 	unsigned long old_min; | 
					
						
							|  |  |  | 	int write_max_first; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!policy || !(policy->governor)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (policy->max < policy->min) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (verify_gov(gov, policy->governor)) | 
					
						
							|  |  |  | 		return -EINVAL; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(min, SYSFS_PATH_MAX, "%lu", policy->min); | 
					
						
							|  |  |  | 	snprintf(max, SYSFS_PATH_MAX, "%lu", policy->max); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	old_min = sysfs_cpufreq_get_one_value(cpu, SCALING_MIN_FREQ); | 
					
						
							|  |  |  | 	write_max_first = (old_min && (policy->max < old_min) ? 0 : 1); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (write_max_first) { | 
					
						
							|  |  |  | 		ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | 
					
						
							|  |  |  | 						    max, strlen(max)); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MIN_FREQ, min, | 
					
						
							|  |  |  | 					    strlen(min)); | 
					
						
							|  |  |  | 	if (ret) | 
					
						
							|  |  |  | 		return ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!write_max_first) { | 
					
						
							|  |  |  | 		ret = sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_MAX_FREQ, | 
					
						
							|  |  |  | 						    max, strlen(max)); | 
					
						
							|  |  |  | 		if (ret) | 
					
						
							|  |  |  | 			return ret; | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_GOVERNOR, | 
					
						
							|  |  |  | 					     gov, strlen(gov)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | int sysfs_set_frequency(unsigned int cpu, unsigned long target_frequency) | 
					
						
							|  |  |  | { | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 	struct cpufreq_policy *pol = sysfs_get_freq_policy(cpu); | 
					
						
							|  |  |  | 	char userspace_gov[] = "userspace"; | 
					
						
							|  |  |  | 	char freq[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	int ret; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (!pol) | 
					
						
							|  |  |  | 		return -ENODEV; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	if (strncmp(pol->governor, userspace_gov, 9) != 0) { | 
					
						
							|  |  |  | 		ret = sysfs_modify_freq_policy_governor(cpu, userspace_gov); | 
					
						
							|  |  |  | 		if (ret) { | 
					
						
							|  |  |  | 			cpufreq_put_policy(pol); | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 			return ret; | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		} | 
					
						
							|  |  |  | 	} | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	cpufreq_put_policy(pol); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(freq, SYSFS_PATH_MAX, "%lu", target_frequency); | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return sysfs_cpufreq_write_one_value(cpu, WRITE_SCALING_SET_SPEED, | 
					
						
							|  |  |  | 					     freq, strlen(freq)); | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* CPUFREQ sysfs access **************************************************/ | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* General sysfs access **************************************************/ | 
					
						
							|  |  |  | int sysfs_cpu_exists(unsigned int cpu) | 
					
						
							|  |  |  | { | 
					
						
							|  |  |  | 	char file[SYSFS_PATH_MAX]; | 
					
						
							|  |  |  | 	struct stat statbuf; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/", cpu); | 
					
						
							|  |  |  | 
 | 
					
						
							| 
									
										
										
										
											2011-04-19 19:42:33 +02:00
										 |  |  | 	if (stat(file, &statbuf) != 0) | 
					
						
							| 
									
										
										
										
											2011-03-30 16:30:11 +02:00
										 |  |  | 		return -ENOSYS; | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | 	return S_ISDIR(statbuf.st_mode) ? 0 : -ENOSYS; | 
					
						
							|  |  |  | } | 
					
						
							|  |  |  | 
 | 
					
						
							|  |  |  | /* General sysfs access **************************************************/ |