Commit 0924c369 authored by Thomas Renninger's avatar Thomas Renninger Committed by Rafael J. Wysocki

cpupower: Implement disabling of cstate interface

Latest kernel allows to disable C-states via:
/sys/devices/system/cpu/cpuX/cpuidle/stateY/disable

This patch provides lower level sysfs access functions to make use of
this interface.  A later patch will implement the higher level stuff.
Signed-off-by: default avatarThomas Renninger <trenn@suse.de>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent f605181a
...@@ -87,8 +87,35 @@ int sysfs_is_cpu_online(unsigned int cpu) ...@@ -87,8 +87,35 @@ int sysfs_is_cpu_online(unsigned int cpu)
return value; return value;
} }
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
/*
* helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
* exists.
* For example the functionality to disable c-states was introduced in later
* kernel versions, this function can be used to explicitly check for this
* feature.
*
* returns 1 if the file exists, 0 otherwise.
*/
unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
unsigned int idlestate,
const char *fname)
{
char path[SYSFS_PATH_MAX];
struct stat statbuf;
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
cpu, idlestate, fname);
if (stat(path, &statbuf) != 0)
return 0;
return 1;
}
/* /*
* helper function to read file from /sys into given buffer * helper function to read file from /sys into given buffer
* fname is a relative path under "cpuX/cpuidle/stateX/" dir * fname is a relative path under "cpuX/cpuidle/stateX/" dir
...@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate, ...@@ -121,6 +148,40 @@ unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
return (unsigned int) numread; return (unsigned int) numread;
} }
/*
* helper function to write a new value to a /sys file
* fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
*
* Returns the number of bytes written or 0 on error
*/
static
unsigned int sysfs_idlestate_write_file(unsigned int cpu,
unsigned int idlestate,
const char *fname,
const char *value, size_t len)
{
char path[SYSFS_PATH_MAX];
int fd;
ssize_t numwrite;
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
cpu, idlestate, fname);
fd = open(path, O_WRONLY);
if (fd == -1)
return 0;
numwrite = write(fd, value, len);
if (numwrite < 1) {
close(fd);
return 0;
}
close(fd);
return (unsigned int) numwrite;
}
/* read access to files which contain one numeric value */ /* read access to files which contain one numeric value */
enum idlestate_value { enum idlestate_value {
...@@ -128,6 +189,7 @@ enum idlestate_value { ...@@ -128,6 +189,7 @@ enum idlestate_value {
IDLESTATE_POWER, IDLESTATE_POWER,
IDLESTATE_LATENCY, IDLESTATE_LATENCY,
IDLESTATE_TIME, IDLESTATE_TIME,
IDLESTATE_DISABLE,
MAX_IDLESTATE_VALUE_FILES MAX_IDLESTATE_VALUE_FILES
}; };
...@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { ...@@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
[IDLESTATE_POWER] = "power", [IDLESTATE_POWER] = "power",
[IDLESTATE_LATENCY] = "latency", [IDLESTATE_LATENCY] = "latency",
[IDLESTATE_TIME] = "time", [IDLESTATE_TIME] = "time",
[IDLESTATE_DISABLE] = "disable",
}; };
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
...@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu, ...@@ -205,8 +268,59 @@ static char *sysfs_idlestate_get_one_string(unsigned int cpu,
return result; return result;
} }
/*
* Returns:
* 1 if disabled
* 0 if enabled
* -1 if idlestate is not available
* -2 if disabling is not supported by the kernel
*/
int sysfs_is_idlestate_disabled(unsigned int cpu,
unsigned int idlestate)
{
if (sysfs_get_idlestate_count(cpu) < idlestate)
return -1;
if (!sysfs_idlestate_file_exists(cpu, idlestate,
idlestate_value_files[IDLESTATE_DISABLE]))
return -2;
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
}
/*
* Pass 1 as last argument to disable or 0 to enable the state
* Returns:
* 0 on success
* negative values on error, for example:
* -1 if idlestate is not available
* -2 if disabling is not supported by the kernel
* -3 No write access to disable/enable C-states
*/
int sysfs_idlestate_disable(unsigned int cpu,
unsigned int idlestate,
unsigned int disable)
{
char value[SYSFS_PATH_MAX];
int bytes_written;
if (sysfs_get_idlestate_count(cpu) < idlestate)
return -1;
if (!sysfs_idlestate_file_exists(cpu, idlestate,
idlestate_value_files[IDLESTATE_DISABLE]))
return -2;
snprintf(value, SYSFS_PATH_MAX, "%u", disable);
bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
value, sizeof(disable));
if (bytes_written)
return 0;
return -3;
}
unsigned long sysfs_get_idlestate_latency(unsigned int cpu, unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate) unsigned int idlestate)
{ {
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
} }
......
...@@ -7,8 +7,16 @@ ...@@ -7,8 +7,16 @@
extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen);
extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
unsigned int idlestate,
const char *fname);
extern int sysfs_is_cpu_online(unsigned int cpu); extern int sysfs_is_cpu_online(unsigned int cpu);
extern int sysfs_is_idlestate_disabled(unsigned int cpu,
unsigned int idlestate);
extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate,
unsigned int disable);
extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
unsigned int idlestate); unsigned int idlestate);
extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment