diff options
| author | Thomas Renninger <trenn@suse.de> | 2013-06-28 09:34:30 -0400 |
|---|---|---|
| committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2013-07-04 19:52:19 -0400 |
| commit | 0924c369bc5492cf181a066fc2d459aa18ffa5ac (patch) | |
| tree | da95fc8a244654d0ea196e5e483704566f45ce3d /tools | |
| parent | f605181abd95a109031a23c67a824eb8e5dcfe67 (diff) | |
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: Thomas Renninger <trenn@suse.de>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Diffstat (limited to 'tools')
| -rw-r--r-- | tools/power/cpupower/utils/helpers/sysfs.c | 116 | ||||
| -rw-r--r-- | tools/power/cpupower/utils/helpers/sysfs.h | 8 |
2 files changed, 123 insertions, 1 deletions
diff --git a/tools/power/cpupower/utils/helpers/sysfs.c b/tools/power/cpupower/utils/helpers/sysfs.c index 891f6710d026..5cdc600e8152 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.c +++ b/tools/power/cpupower/utils/helpers/sysfs.c | |||
| @@ -89,6 +89,33 @@ int sysfs_is_cpu_online(unsigned int cpu) | |||
| 89 | 89 | ||
| 90 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | 90 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ |
| 91 | 91 | ||
| 92 | |||
| 93 | /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */ | ||
| 94 | |||
| 95 | /* | ||
| 96 | * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir | ||
| 97 | * exists. | ||
| 98 | * For example the functionality to disable c-states was introduced in later | ||
| 99 | * kernel versions, this function can be used to explicitly check for this | ||
| 100 | * feature. | ||
| 101 | * | ||
| 102 | * returns 1 if the file exists, 0 otherwise. | ||
| 103 | */ | ||
| 104 | unsigned int sysfs_idlestate_file_exists(unsigned int cpu, | ||
| 105 | unsigned int idlestate, | ||
| 106 | const char *fname) | ||
| 107 | { | ||
| 108 | char path[SYSFS_PATH_MAX]; | ||
| 109 | struct stat statbuf; | ||
| 110 | |||
| 111 | |||
| 112 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
| 113 | cpu, idlestate, fname); | ||
| 114 | if (stat(path, &statbuf) != 0) | ||
| 115 | return 0; | ||
| 116 | return 1; | ||
| 117 | } | ||
| 118 | |||
| 92 | /* | 119 | /* |
| 93 | * helper function to read file from /sys into given buffer | 120 | * helper function to read file from /sys into given buffer |
| 94 | * fname is a relative path under "cpuX/cpuidle/stateX/" dir | 121 | * 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 | return (unsigned int) numread; | 148 | return (unsigned int) numread; |
| 122 | } | 149 | } |
| 123 | 150 | ||
| 151 | /* | ||
| 152 | * helper function to write a new value to a /sys file | ||
| 153 | * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir | ||
| 154 | * | ||
| 155 | * Returns the number of bytes written or 0 on error | ||
| 156 | */ | ||
| 157 | static | ||
| 158 | unsigned int sysfs_idlestate_write_file(unsigned int cpu, | ||
| 159 | unsigned int idlestate, | ||
| 160 | const char *fname, | ||
| 161 | const char *value, size_t len) | ||
| 162 | { | ||
| 163 | char path[SYSFS_PATH_MAX]; | ||
| 164 | int fd; | ||
| 165 | ssize_t numwrite; | ||
| 166 | |||
| 167 | snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", | ||
| 168 | cpu, idlestate, fname); | ||
| 169 | |||
| 170 | fd = open(path, O_WRONLY); | ||
| 171 | if (fd == -1) | ||
| 172 | return 0; | ||
| 173 | |||
| 174 | numwrite = write(fd, value, len); | ||
| 175 | if (numwrite < 1) { | ||
| 176 | close(fd); | ||
| 177 | return 0; | ||
| 178 | } | ||
| 179 | |||
| 180 | close(fd); | ||
| 181 | |||
| 182 | return (unsigned int) numwrite; | ||
| 183 | } | ||
| 184 | |||
| 124 | /* read access to files which contain one numeric value */ | 185 | /* read access to files which contain one numeric value */ |
| 125 | 186 | ||
| 126 | enum idlestate_value { | 187 | enum idlestate_value { |
| @@ -128,6 +189,7 @@ enum idlestate_value { | |||
| 128 | IDLESTATE_POWER, | 189 | IDLESTATE_POWER, |
| 129 | IDLESTATE_LATENCY, | 190 | IDLESTATE_LATENCY, |
| 130 | IDLESTATE_TIME, | 191 | IDLESTATE_TIME, |
| 192 | IDLESTATE_DISABLE, | ||
| 131 | MAX_IDLESTATE_VALUE_FILES | 193 | MAX_IDLESTATE_VALUE_FILES |
| 132 | }; | 194 | }; |
| 133 | 195 | ||
| @@ -136,6 +198,7 @@ static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { | |||
| 136 | [IDLESTATE_POWER] = "power", | 198 | [IDLESTATE_POWER] = "power", |
| 137 | [IDLESTATE_LATENCY] = "latency", | 199 | [IDLESTATE_LATENCY] = "latency", |
| 138 | [IDLESTATE_TIME] = "time", | 200 | [IDLESTATE_TIME] = "time", |
| 201 | [IDLESTATE_DISABLE] = "disable", | ||
| 139 | }; | 202 | }; |
| 140 | 203 | ||
| 141 | static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu, | 204 | 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 | return result; | 268 | return result; |
| 206 | } | 269 | } |
| 207 | 270 | ||
| 271 | /* | ||
| 272 | * Returns: | ||
| 273 | * 1 if disabled | ||
| 274 | * 0 if enabled | ||
| 275 | * -1 if idlestate is not available | ||
| 276 | * -2 if disabling is not supported by the kernel | ||
| 277 | */ | ||
| 278 | int sysfs_is_idlestate_disabled(unsigned int cpu, | ||
| 279 | unsigned int idlestate) | ||
| 280 | { | ||
| 281 | if (sysfs_get_idlestate_count(cpu) < idlestate) | ||
| 282 | return -1; | ||
| 283 | |||
| 284 | if (!sysfs_idlestate_file_exists(cpu, idlestate, | ||
| 285 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
| 286 | return -2; | ||
| 287 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); | ||
| 288 | } | ||
| 289 | |||
| 290 | /* | ||
| 291 | * Pass 1 as last argument to disable or 0 to enable the state | ||
| 292 | * Returns: | ||
| 293 | * 0 on success | ||
| 294 | * negative values on error, for example: | ||
| 295 | * -1 if idlestate is not available | ||
| 296 | * -2 if disabling is not supported by the kernel | ||
| 297 | * -3 No write access to disable/enable C-states | ||
| 298 | */ | ||
| 299 | int sysfs_idlestate_disable(unsigned int cpu, | ||
| 300 | unsigned int idlestate, | ||
| 301 | unsigned int disable) | ||
| 302 | { | ||
| 303 | char value[SYSFS_PATH_MAX]; | ||
| 304 | int bytes_written; | ||
| 305 | |||
| 306 | if (sysfs_get_idlestate_count(cpu) < idlestate) | ||
| 307 | return -1; | ||
| 308 | |||
| 309 | if (!sysfs_idlestate_file_exists(cpu, idlestate, | ||
| 310 | idlestate_value_files[IDLESTATE_DISABLE])) | ||
| 311 | return -2; | ||
| 312 | |||
| 313 | snprintf(value, SYSFS_PATH_MAX, "%u", disable); | ||
| 314 | |||
| 315 | bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable", | ||
| 316 | value, sizeof(disable)); | ||
| 317 | if (bytes_written) | ||
| 318 | return 0; | ||
| 319 | return -3; | ||
| 320 | } | ||
| 321 | |||
| 208 | unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | 322 | unsigned long sysfs_get_idlestate_latency(unsigned int cpu, |
| 209 | unsigned int idlestate) | 323 | unsigned int idlestate) |
| 210 | { | 324 | { |
| 211 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); | 325 | return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); |
| 212 | } | 326 | } |
diff --git a/tools/power/cpupower/utils/helpers/sysfs.h b/tools/power/cpupower/utils/helpers/sysfs.h index 0401a97a4cab..d28f11fedbda 100644 --- a/tools/power/cpupower/utils/helpers/sysfs.h +++ b/tools/power/cpupower/utils/helpers/sysfs.h | |||
| @@ -7,8 +7,16 @@ | |||
| 7 | 7 | ||
| 8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); | 8 | extern unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen); |
| 9 | 9 | ||
| 10 | extern unsigned int sysfs_idlestate_file_exists(unsigned int cpu, | ||
| 11 | unsigned int idlestate, | ||
| 12 | const char *fname); | ||
| 13 | |||
| 10 | extern int sysfs_is_cpu_online(unsigned int cpu); | 14 | extern int sysfs_is_cpu_online(unsigned int cpu); |
| 11 | 15 | ||
| 16 | extern int sysfs_is_idlestate_disabled(unsigned int cpu, | ||
| 17 | unsigned int idlestate); | ||
| 18 | extern int sysfs_idlestate_disable(unsigned int cpu, unsigned int idlestate, | ||
| 19 | unsigned int disable); | ||
| 12 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, | 20 | extern unsigned long sysfs_get_idlestate_latency(unsigned int cpu, |
| 13 | unsigned int idlestate); | 21 | unsigned int idlestate); |
| 14 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, | 22 | extern unsigned long sysfs_get_idlestate_usage(unsigned int cpu, |
