1
0
Fork 0
dockapps/wmpower/src/power_management/cpufreq/cpufreq.c
Alexey I. Froloff 792a5d290a Mass update FSF address
Signed-off-by: Alexey I. Froloff <raorn@raorn.name>
2012-06-05 20:50:13 +01:00

378 lines
9.5 KiB
C

/***************************************************************************
cpufreq.c - description
-------------------
begin : Feb 10 2003
copyright : (C) 2003,2004,2005 by Noberasco Michele
e-mail : s4t4n@gentoo.org
***************************************************************************/
/***************************************************************************
* *
* This program is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This program is distributed in the hope that it will be useful, *
* but WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the *
* GNU General Public License for more details. *
* *
* You should have received a copy of the GNU General Public License *
* along with this program; if not, write to the *
* Free Software Foundation, Inc., *
* 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. *
* *
***************************************************************************/
#define SYSFS_CPU_BASE_DIR "/sys/devices/system/cpu"
#define SYSFS_CPUFREQ_TEST "affected_cpus"
#define SYSFS_CPUFREQ_AVAIL_GOV "scaling_available_governors"
#define SYSFS_CPUFREQ_SET_GOV "scaling_governor"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <dirent.h>
#include <unistd.h>
#include <sys/types.h>
#include "power_management.h"
#include "lib_utils.h"
/* This will contain a list of CPU that we will manage through cpufreq */
struct cpufreq_available_cpus
{
int cpu_number;
char *dir_name;
struct cpufreq_available_cpus *next;
} *available_cpus = NULL;
/* Add one element to the list of CPUs available for frequency scaling */
void add_to_cpus_list(int cpu_number, char *path)
{
struct cpufreq_available_cpus *new_cpu;
if (!path) return;
new_cpu = (struct cpufreq_available_cpus *) calloc(1, sizeof(struct cpufreq_available_cpus));
if (!new_cpu)
{
fprintf(stderr, "allocation failure!\n");
abort();
}
new_cpu->cpu_number = cpu_number;
new_cpu->dir_name = path;
new_cpu->next = NULL;
if (available_cpus)
{ /* we navigate to the bottom of the list... */
struct cpufreq_available_cpus *curr_cpu = available_cpus;
for (; curr_cpu->next != NULL; curr_cpu=curr_cpu->next);
curr_cpu->next = new_cpu;
return;
}
available_cpus = new_cpu;
}
/* check CPUfreq support via the sysfs file system */
int check_cpufreq_2_6(void)
{
DIR *dir = opendir(SYSFS_CPU_BASE_DIR);
struct dirent *entry;
/* How many CPUs do we have? */
if (!dir) return 0;
while ((entry= readdir(dir)))
{
size_t len = 0;
char *line = NULL;
char *test;
char *filename;
FILE *fp;
if (!strcmp(entry->d_name, "." )) continue;
if (!strcmp(entry->d_name, "..")) continue;
if (strncmp(entry->d_name, "cpu", 3)) continue;
/* let's see wether this particular CPU has CPUfreq support... */
filename = StrApp((char**)NULL, SYSFS_CPU_BASE_DIR, "/", entry->d_name, "/cpufreq/", SYSFS_CPUFREQ_TEST, (char*)NULL);
fp = fopen(filename, "r");
if (!fp)
{ /* no good... */
free(filename);
continue;
}
if (getline(&line, &len, fp) == -1)
{ /* no good... */
free(filename);
fclose(fp);
continue;
}
fclose(fp);
test = (char *) calloc(strlen(line)+1, sizeof(char));
if (!test)
{
fprintf(stderr, "allocation failure!\n");
abort();
}
while (sscanf(line, "%s", test) != EOF)
/* let's see wether we can find a cpu number equal to our one in test file... */
if (!strcmp((entry->d_name)+3, test))
{ /* Got it! */
int cpu_number = atoi(entry->d_name + 3) + 1;
add_to_cpus_list(cpu_number, StrApp((char**)NULL, SYSFS_CPU_BASE_DIR, "/", entry->d_name, "/cpufreq/", (char*)NULL));
break;
}
/* no good.. */
free(filename);
free(test);
free(line);
}
closedir(dir);
/* did we get results? */
if (available_cpus) return 1;
/* What a shame, all these CPU cycles for nothing! */
return 0;
}
/* Checks wether this machine supports CPU frequency scaling,
* and builds a list of CPUs available for that...
*/
int check_cpufreq(void)
{
if (kernel_version == IS_2_6)
return check_cpufreq_2_6();
/* 2.4 kernels are not supported at the moment... */
return 0;
}
char *cpufreq_get_governor_2_6(int cpu)
{
struct cpufreq_available_cpus *curr_cpu = available_cpus;
char *filename;
FILE *fp;
size_t len = 0;
char *line = NULL;
char *test;
for (; curr_cpu!=NULL; curr_cpu=curr_cpu->next)
if (curr_cpu->cpu_number == cpu)
break;
if (curr_cpu->cpu_number != cpu) return NULL;
filename = StrApp((char**)NULL, curr_cpu->dir_name, SYSFS_CPUFREQ_SET_GOV, (char*)NULL);
fp = fopen(filename, "r");
if (!fp)
{
free(filename);
return NULL;
}
if (getline(&line, &len, fp) == -1)
{
fprintf(stderr, "could not read from file %s!\n", filename);
free(filename);
fclose(fp);
return NULL;
}
fclose(fp);
free(filename);
test = (char*) calloc(strlen(line)+1,sizeof(char));
if (!test)
{
fprintf(stderr, "failure allocating memory!\n");
abort();
}
if (sscanf(line, "%s", test) != 1)
{
free(test);
free(line);
return NULL;
}
free(line);
return test;
}
/* Get cpufreq governor of CPU #n, where 1<=n<=MAX, where MAX is
* the number of CPUs you have in your system
*/
char *cpufreq_get_governor(int cpu)
{
if (cpu < 1) return NULL;
if (kernel_version == IS_2_6)
return cpufreq_get_governor_2_6(cpu);
/* 2.4 kernels are not supported at the moment... */
return NULL;
}
/* set CPUfreq governor via the sysfs file system */
int set_cpufreq_governor_2_6(char *governor)
{
struct cpufreq_available_cpus *curr_cpu=available_cpus;
int retval = 1;
/* Set desired governor for all available CPUs */
for (; curr_cpu!=NULL; curr_cpu=curr_cpu->next)
{
FILE *fp;
char *filename;
int supported = 0;
fprintf(stderr, "Setting CPU scaling governor \"%s\" for CPU %d...\n", governor, curr_cpu->cpu_number);
/* check wether this CPU supports the specified governor */
filename = StrApp((char**)NULL, curr_cpu->dir_name, SYSFS_CPUFREQ_AVAIL_GOV, (char*)NULL);
fp = fopen(filename, "r");
if (!fp)
{
fprintf(stderr, "could not open file %s!\n", filename);
free(filename);
retval = 0;
continue;
}
else
{
size_t len = 0;
char *line = NULL;
char *test;
int cont = 0;
if (getline(&line, &len, fp) == -1)
{
fprintf(stderr, "could not read from file %s!\n", filename);
free(filename);
fclose(fp);
retval = 0;
continue;
}
fclose(fp);
test = (char *) calloc(strlen(line)+1, sizeof(char));
if (!test)
{
fprintf(stderr, "failure allocating memory!\n");
abort();
}
while (sscanf(line+cont, "%s", test) != EOF)
{
if (!strcmp(test, governor))
{
supported = 1;
break;
}
cont = strstr(line, test) - line + strlen(test);
}
free(test);
free(line);
}
free(filename);
if (!supported)
{
fprintf(stderr, "sorry, this CPU does not support the speficied CPUfreq governor...\n");
retval = 0;
continue;
}
/* OK, let's set the specified governor for this CPU */
filename = StrApp((char**)NULL, curr_cpu->dir_name, SYSFS_CPUFREQ_SET_GOV, (char*)NULL);
fp = fopen(filename, "w");
if (!fp)
{
fprintf(stderr, "could not open file %s for writing!\n", filename);
free(filename);
retval = 0;
continue;
}
if (fprintf(fp, "%s", governor) <= 0)
{
fprintf(stderr, "failed writing to file %s!\n", filename);
free(filename);
fclose(fp);
retval = 0;
continue;
}
fclose(fp);
/* OK, we supposedly set our governor on this CPU, let's see wether it actually went through... */
fp = fopen(filename, "r");
if (!fp)
{
fprintf(stderr, "could not open file %s for reading!\n", filename);
free(filename);
retval = 0;
continue;
}
else
{
size_t len = 0;
char *line = NULL;
char *test;
if (getline(&line, &len, fp) == -1)
{
fprintf(stderr, "could not read from file %s!\n", filename);
free(filename);
fclose(fp);
retval = 0;
continue;
}
fclose(fp);
test = (char *) calloc(strlen(line)+1,sizeof(char));
if (!test)
{
fprintf(stderr, "failure allocating memory!\n");
abort();
}
if (sscanf(line, "%s", test) != 1)
{
fprintf(stderr, "could not read from file %s!\n", filename);
free(filename);
free(test);
free(line);
retval = 0;
continue;
}
free(line);
if (strcmp(test, governor))
{
fprintf(stderr, "failed setting specified CPUfreq governor!\n");
retval = 0;
}
free(test);
}
}
return retval;
}
/* Set cpufreq governor */
int cpufreq_set_governor(char *governor)
{
if (!governor) return 0;
if (!available_cpus) return 0;
if (!strlen(governor)) return 0;
if (kernel_version == IS_2_6)
return set_cpufreq_governor_2_6(governor);
/* 2.4 kernels are not supported at the moment */
return 0;
}