Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux
1
fork

Configure Feed

Select the types of activity you want to include in your feed.

at v4.8-rc6 380 lines 8.8 kB view raw
1/* 2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de> 3 * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc. 4 * 5 * Licensed under the terms of the GNU GPL License version 2. 6 */ 7 8#include <stdio.h> 9#include <errno.h> 10#include <stdlib.h> 11#include <string.h> 12#include <sys/types.h> 13#include <sys/stat.h> 14#include <fcntl.h> 15#include <unistd.h> 16 17#include "cpuidle.h" 18#include "cpupower_intern.h" 19 20/* 21 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir 22 * exists. 23 * For example the functionality to disable c-states was introduced in later 24 * kernel versions, this function can be used to explicitly check for this 25 * feature. 26 * 27 * returns 1 if the file exists, 0 otherwise. 28 */ 29static 30unsigned int cpuidle_state_file_exists(unsigned int cpu, 31 unsigned int idlestate, 32 const char *fname) 33{ 34 char path[SYSFS_PATH_MAX]; 35 struct stat statbuf; 36 37 38 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", 39 cpu, idlestate, fname); 40 if (stat(path, &statbuf) != 0) 41 return 0; 42 return 1; 43} 44 45/* 46 * helper function to read file from /sys into given buffer 47 * fname is a relative path under "cpuX/cpuidle/stateX/" dir 48 * cstates starting with 0, C0 is not counted as cstate. 49 * This means if you want C1 info, pass 0 as idlestate param 50 */ 51static 52unsigned int cpuidle_state_read_file(unsigned int cpu, 53 unsigned int idlestate, 54 const char *fname, char *buf, 55 size_t buflen) 56{ 57 char path[SYSFS_PATH_MAX]; 58 int fd; 59 ssize_t numread; 60 61 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", 62 cpu, idlestate, fname); 63 64 fd = open(path, O_RDONLY); 65 if (fd == -1) 66 return 0; 67 68 numread = read(fd, buf, buflen - 1); 69 if (numread < 1) { 70 close(fd); 71 return 0; 72 } 73 74 buf[numread] = '\0'; 75 close(fd); 76 77 return (unsigned int) numread; 78} 79 80/* 81 * helper function to write a new value to a /sys file 82 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir 83 * 84 * Returns the number of bytes written or 0 on error 85 */ 86static 87unsigned int cpuidle_state_write_file(unsigned int cpu, 88 unsigned int idlestate, 89 const char *fname, 90 const char *value, size_t len) 91{ 92 char path[SYSFS_PATH_MAX]; 93 int fd; 94 ssize_t numwrite; 95 96 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s", 97 cpu, idlestate, fname); 98 99 fd = open(path, O_WRONLY); 100 if (fd == -1) 101 return 0; 102 103 numwrite = write(fd, value, len); 104 if (numwrite < 1) { 105 close(fd); 106 return 0; 107 } 108 109 close(fd); 110 111 return (unsigned int) numwrite; 112} 113 114/* read access to files which contain one numeric value */ 115 116enum idlestate_value { 117 IDLESTATE_USAGE, 118 IDLESTATE_POWER, 119 IDLESTATE_LATENCY, 120 IDLESTATE_TIME, 121 IDLESTATE_DISABLE, 122 MAX_IDLESTATE_VALUE_FILES 123}; 124 125static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = { 126 [IDLESTATE_USAGE] = "usage", 127 [IDLESTATE_POWER] = "power", 128 [IDLESTATE_LATENCY] = "latency", 129 [IDLESTATE_TIME] = "time", 130 [IDLESTATE_DISABLE] = "disable", 131}; 132 133static 134unsigned long long cpuidle_state_get_one_value(unsigned int cpu, 135 unsigned int idlestate, 136 enum idlestate_value which) 137{ 138 unsigned long long value; 139 unsigned int len; 140 char linebuf[MAX_LINE_LEN]; 141 char *endp; 142 143 if (which >= MAX_IDLESTATE_VALUE_FILES) 144 return 0; 145 146 len = cpuidle_state_read_file(cpu, idlestate, 147 idlestate_value_files[which], 148 linebuf, sizeof(linebuf)); 149 if (len == 0) 150 return 0; 151 152 value = strtoull(linebuf, &endp, 0); 153 154 if (endp == linebuf || errno == ERANGE) 155 return 0; 156 157 return value; 158} 159 160/* read access to files which contain one string */ 161 162enum idlestate_string { 163 IDLESTATE_DESC, 164 IDLESTATE_NAME, 165 MAX_IDLESTATE_STRING_FILES 166}; 167 168static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = { 169 [IDLESTATE_DESC] = "desc", 170 [IDLESTATE_NAME] = "name", 171}; 172 173 174static char *cpuidle_state_get_one_string(unsigned int cpu, 175 unsigned int idlestate, 176 enum idlestate_string which) 177{ 178 char linebuf[MAX_LINE_LEN]; 179 char *result; 180 unsigned int len; 181 182 if (which >= MAX_IDLESTATE_STRING_FILES) 183 return NULL; 184 185 len = cpuidle_state_read_file(cpu, idlestate, 186 idlestate_string_files[which], 187 linebuf, sizeof(linebuf)); 188 if (len == 0) 189 return NULL; 190 191 result = strdup(linebuf); 192 if (result == NULL) 193 return NULL; 194 195 if (result[strlen(result) - 1] == '\n') 196 result[strlen(result) - 1] = '\0'; 197 198 return result; 199} 200 201/* 202 * Returns: 203 * 1 if disabled 204 * 0 if enabled 205 * -1 if idlestate is not available 206 * -2 if disabling is not supported by the kernel 207 */ 208int cpuidle_is_state_disabled(unsigned int cpu, 209 unsigned int idlestate) 210{ 211 if (cpuidle_state_count(cpu) <= idlestate) 212 return -1; 213 214 if (!cpuidle_state_file_exists(cpu, idlestate, 215 idlestate_value_files[IDLESTATE_DISABLE])) 216 return -2; 217 return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE); 218} 219 220/* 221 * Pass 1 as last argument to disable or 0 to enable the state 222 * Returns: 223 * 0 on success 224 * negative values on error, for example: 225 * -1 if idlestate is not available 226 * -2 if disabling is not supported by the kernel 227 * -3 No write access to disable/enable C-states 228 */ 229int cpuidle_state_disable(unsigned int cpu, 230 unsigned int idlestate, 231 unsigned int disable) 232{ 233 char value[SYSFS_PATH_MAX]; 234 int bytes_written; 235 236 if (cpuidle_state_count(cpu) <= idlestate) 237 return -1; 238 239 if (!cpuidle_state_file_exists(cpu, idlestate, 240 idlestate_value_files[IDLESTATE_DISABLE])) 241 return -2; 242 243 snprintf(value, SYSFS_PATH_MAX, "%u", disable); 244 245 bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable", 246 value, sizeof(disable)); 247 if (bytes_written) 248 return 0; 249 return -3; 250} 251 252unsigned long cpuidle_state_latency(unsigned int cpu, 253 unsigned int idlestate) 254{ 255 return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY); 256} 257 258unsigned long cpuidle_state_usage(unsigned int cpu, 259 unsigned int idlestate) 260{ 261 return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE); 262} 263 264unsigned long long cpuidle_state_time(unsigned int cpu, 265 unsigned int idlestate) 266{ 267 return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME); 268} 269 270char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate) 271{ 272 return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME); 273} 274 275char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate) 276{ 277 return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC); 278} 279 280/* 281 * Returns number of supported C-states of CPU core cpu 282 * Negativ in error case 283 * Zero if cpuidle does not export any C-states 284 */ 285unsigned int cpuidle_state_count(unsigned int cpu) 286{ 287 char file[SYSFS_PATH_MAX]; 288 struct stat statbuf; 289 int idlestates = 1; 290 291 292 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle"); 293 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) 294 return 0; 295 296 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu); 297 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode)) 298 return 0; 299 300 while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) { 301 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU 302 "cpu%u/cpuidle/state%d", cpu, idlestates); 303 idlestates++; 304 } 305 idlestates--; 306 return idlestates; 307} 308 309/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/ 310 311/* 312 * helper function to read file from /sys into given buffer 313 * fname is a relative path under "cpu/cpuidle/" dir 314 */ 315static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf, 316 size_t buflen) 317{ 318 char path[SYSFS_PATH_MAX]; 319 320 snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname); 321 322 return sysfs_read_file(path, buf, buflen); 323} 324 325 326 327/* read access to files which contain one string */ 328 329enum cpuidle_string { 330 CPUIDLE_GOVERNOR, 331 CPUIDLE_GOVERNOR_RO, 332 CPUIDLE_DRIVER, 333 MAX_CPUIDLE_STRING_FILES 334}; 335 336static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = { 337 [CPUIDLE_GOVERNOR] = "current_governor", 338 [CPUIDLE_GOVERNOR_RO] = "current_governor_ro", 339 [CPUIDLE_DRIVER] = "current_driver", 340}; 341 342 343static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which) 344{ 345 char linebuf[MAX_LINE_LEN]; 346 char *result; 347 unsigned int len; 348 349 if (which >= MAX_CPUIDLE_STRING_FILES) 350 return NULL; 351 352 len = sysfs_cpuidle_read_file(cpuidle_string_files[which], 353 linebuf, sizeof(linebuf)); 354 if (len == 0) 355 return NULL; 356 357 result = strdup(linebuf); 358 if (result == NULL) 359 return NULL; 360 361 if (result[strlen(result) - 1] == '\n') 362 result[strlen(result) - 1] = '\0'; 363 364 return result; 365} 366 367char *cpuidle_get_governor(void) 368{ 369 char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO); 370 if (!tmp) 371 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR); 372 else 373 return tmp; 374} 375 376char *cpuidle_get_driver(void) 377{ 378 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER); 379} 380/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */