1 /***************************************************************************
2 cpufreq.c - description
5 copyright : (C) 2003,2004,2005 by Noberasco Michele
6 e-mail : s4t4n@gentoo.org
7 ***************************************************************************/
9 /***************************************************************************
11 * This program is free software; you can redistribute it and/or modify *
12 * it under the terms of the GNU General Public License as published by *
13 * the Free Software Foundation; either version 2 of the License, or *
14 * (at your option) any later version. *
16 * This program is distributed in the hope that it will be useful, *
17 * but WITHOUT ANY WARRANTY; without even the implied warranty of *
18 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
19 * GNU General Public License for more details. *
21 * You should have received a copy of the GNU General Public License *
22 * along with this program; if not, write to the *
23 * Free Software Foundation, Inc., *
24 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
26 ***************************************************************************/
29 #define SYSFS_CPU_BASE_DIR "/sys/devices/system/cpu"
30 #define SYSFS_CPUFREQ_TEST "affected_cpus"
31 #define SYSFS_CPUFREQ_AVAIL_GOV "scaling_available_governors"
32 #define SYSFS_CPUFREQ_SET_GOV "scaling_governor"
39 #include <sys/types.h>
40 #include "power_management.h"
41 #include "lib_utils.h"
44 /* This will contain a list of CPU that we will manage through cpufreq */
45 struct cpufreq_available_cpus
49 struct cpufreq_available_cpus
*next
;
50 } *available_cpus
= NULL
;
53 /* Add one element to the list of CPUs available for frequency scaling */
54 void add_to_cpus_list(int cpu_number
, char *path
)
56 struct cpufreq_available_cpus
*new_cpu
;
60 new_cpu
= (struct cpufreq_available_cpus
*) calloc(1, sizeof(struct cpufreq_available_cpus
));
63 fprintf(stderr
, "allocation failure!\n");
66 new_cpu
->cpu_number
= cpu_number
;
67 new_cpu
->dir_name
= path
;
71 { /* we navigate to the bottom of the list... */
72 struct cpufreq_available_cpus
*curr_cpu
= available_cpus
;
73 for (; curr_cpu
->next
!= NULL
; curr_cpu
=curr_cpu
->next
);
74 curr_cpu
->next
= new_cpu
;
78 available_cpus
= new_cpu
;
81 /* check CPUfreq support via the sysfs file system */
82 int check_cpufreq_2_6(void)
84 DIR *dir
= opendir(SYSFS_CPU_BASE_DIR
);
87 /* How many CPUs do we have? */
89 while ((entry
= readdir(dir
)))
97 if (!strcmp(entry
->d_name
, "." )) continue;
98 if (!strcmp(entry
->d_name
, "..")) continue;
99 if (strncmp(entry
->d_name
, "cpu", 3)) continue;
101 /* let's see wether this particular CPU has CPUfreq support... */
102 filename
= StrApp((char**)NULL
, SYSFS_CPU_BASE_DIR
, "/", entry
->d_name
, "/cpufreq/", SYSFS_CPUFREQ_TEST
, (char*)NULL
);
103 fp
= fopen(filename
, "r");
109 if (getline(&line
, &len
, fp
) == -1)
116 test
= (char *) calloc(strlen(line
)+1, sizeof(char));
119 fprintf(stderr
, "allocation failure!\n");
122 while (sscanf(line
, "%s", test
) != EOF
)
123 /* let's see wether we can find a cpu number equal to our one in test file... */
124 if (!strcmp((entry
->d_name
)+3, test
))
126 int cpu_number
= atoi(entry
->d_name
+ 3) + 1;
127 add_to_cpus_list(cpu_number
, StrApp((char**)NULL
, SYSFS_CPU_BASE_DIR
, "/", entry
->d_name
, "/cpufreq/", (char*)NULL
));
137 /* did we get results? */
138 if (available_cpus
) return 1;
140 /* What a shame, all these CPU cycles for nothing! */
144 /* Checks wether this machine supports CPU frequency scaling,
145 * and builds a list of CPUs available for that...
147 int check_cpufreq(void)
149 if (kernel_version
== IS_2_6
)
150 return check_cpufreq_2_6();
152 /* 2.4 kernels are not supported at the moment... */
157 char *cpufreq_get_governor_2_6(int cpu
)
159 struct cpufreq_available_cpus
*curr_cpu
= available_cpus
;
166 for (; curr_cpu
!=NULL
; curr_cpu
=curr_cpu
->next
)
167 if (curr_cpu
->cpu_number
== cpu
)
170 if (curr_cpu
->cpu_number
!= cpu
) return NULL
;
172 filename
= StrApp((char**)NULL
, curr_cpu
->dir_name
, SYSFS_CPUFREQ_SET_GOV
, (char*)NULL
);
173 fp
= fopen(filename
, "r");
181 if (getline(&line
, &len
, fp
) == -1)
183 fprintf(stderr
, "could not read from file %s!\n", filename
);
191 test
= (char*) calloc(strlen(line
)+1,sizeof(char));
194 fprintf(stderr
, "failure allocating memory!\n");
197 if (sscanf(line
, "%s", test
) != 1)
208 /* Get cpufreq governor of CPU #n, where 1<=n<=MAX, where MAX is
209 * the number of CPUs you have in your system
211 char *cpufreq_get_governor(int cpu
)
213 if (cpu
< 1) return NULL
;
215 if (kernel_version
== IS_2_6
)
216 return cpufreq_get_governor_2_6(cpu
);
218 /* 2.4 kernels are not supported at the moment... */
223 /* set CPUfreq governor via the sysfs file system */
224 int set_cpufreq_governor_2_6(char *governor
)
226 struct cpufreq_available_cpus
*curr_cpu
=available_cpus
;
229 /* Set desired governor for all available CPUs */
230 for (; curr_cpu
!=NULL
; curr_cpu
=curr_cpu
->next
)
236 fprintf(stderr
, "Setting CPU scaling governor \"%s\" for CPU %d...\n", governor
, curr_cpu
->cpu_number
);
238 /* check wether this CPU supports the specified governor */
239 filename
= StrApp((char**)NULL
, curr_cpu
->dir_name
, SYSFS_CPUFREQ_AVAIL_GOV
, (char*)NULL
);
240 fp
= fopen(filename
, "r");
243 fprintf(stderr
, "could not open file %s!\n", filename
);
255 if (getline(&line
, &len
, fp
) == -1)
257 fprintf(stderr
, "could not read from file %s!\n", filename
);
265 test
= (char *) calloc(strlen(line
)+1, sizeof(char));
268 fprintf(stderr
, "failure allocating memory!\n");
272 while (sscanf(line
+cont
, "%s", test
) != EOF
)
274 if (!strcmp(test
, governor
))
279 cont
= strstr(line
, test
) - line
+ strlen(test
);
287 fprintf(stderr
, "sorry, this CPU does not support the speficied CPUfreq governor...\n");
292 /* OK, let's set the specified governor for this CPU */
293 filename
= StrApp((char**)NULL
, curr_cpu
->dir_name
, SYSFS_CPUFREQ_SET_GOV
, (char*)NULL
);
295 fp
= fopen(filename
, "w");
298 fprintf(stderr
, "could not open file %s for writing!\n", filename
);
303 if (fprintf(fp
, "%s", governor
) <= 0)
305 fprintf(stderr
, "failed writing to file %s!\n", filename
);
312 /* OK, we supposedly set our governor on this CPU, let's see wether it actually went through... */
313 fp
= fopen(filename
, "r");
316 fprintf(stderr
, "could not open file %s for reading!\n", filename
);
327 if (getline(&line
, &len
, fp
) == -1)
329 fprintf(stderr
, "could not read from file %s!\n", filename
);
336 test
= (char *) calloc(strlen(line
)+1,sizeof(char));
339 fprintf(stderr
, "failure allocating memory!\n");
342 if (sscanf(line
, "%s", test
) != 1)
344 fprintf(stderr
, "could not read from file %s!\n", filename
);
352 if (strcmp(test
, governor
))
354 fprintf(stderr
, "failed setting specified CPUfreq governor!\n");
364 /* Set cpufreq governor */
365 int cpufreq_set_governor(char *governor
)
367 if (!governor
) return 0;
368 if (!available_cpus
) return 0;
369 if (!strlen(governor
)) return 0;
371 if (kernel_version
== IS_2_6
)
372 return set_cpufreq_governor_2_6(governor
);
375 /* 2.4 kernels are not supported at the moment */