2 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
3 * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
5 * Licensed under the terms of the GNU GPL License version 2.
12 #include <sys/types.h>
18 #include "cpupower_intern.h"
21 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
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
27 * returns 1 if the file exists, 0 otherwise.
30 unsigned int cpuidle_state_file_exists(unsigned int cpu
,
31 unsigned int idlestate
,
34 char path
[SYSFS_PATH_MAX
];
38 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
39 cpu
, idlestate
, fname
);
40 if (stat(path
, &statbuf
) != 0)
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
52 unsigned int cpuidle_state_read_file(unsigned int cpu
,
53 unsigned int idlestate
,
54 const char *fname
, char *buf
,
57 char path
[SYSFS_PATH_MAX
];
61 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
62 cpu
, idlestate
, fname
);
64 fd
= open(path
, O_RDONLY
);
68 numread
= read(fd
, buf
, buflen
- 1);
77 return (unsigned int) numread
;
81 * helper function to write a new value to a /sys file
82 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
84 * Returns the number of bytes written or 0 on error
87 unsigned int cpuidle_state_write_file(unsigned int cpu
,
88 unsigned int idlestate
,
90 const char *value
, size_t len
)
92 char path
[SYSFS_PATH_MAX
];
96 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
97 cpu
, idlestate
, fname
);
99 fd
= open(path
, O_WRONLY
);
103 numwrite
= write(fd
, value
, len
);
111 return (unsigned int) numwrite
;
114 /* read access to files which contain one numeric value */
116 enum idlestate_value
{
122 MAX_IDLESTATE_VALUE_FILES
125 static 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",
134 unsigned long long cpuidle_state_get_one_value(unsigned int cpu
,
135 unsigned int idlestate
,
136 enum idlestate_value which
)
138 unsigned long long value
;
140 char linebuf
[MAX_LINE_LEN
];
143 if (which
>= MAX_IDLESTATE_VALUE_FILES
)
146 len
= cpuidle_state_read_file(cpu
, idlestate
,
147 idlestate_value_files
[which
],
148 linebuf
, sizeof(linebuf
));
152 value
= strtoull(linebuf
, &endp
, 0);
154 if (endp
== linebuf
|| errno
== ERANGE
)
160 /* read access to files which contain one string */
162 enum idlestate_string
{
165 MAX_IDLESTATE_STRING_FILES
168 static const char *idlestate_string_files
[MAX_IDLESTATE_STRING_FILES
] = {
169 [IDLESTATE_DESC
] = "desc",
170 [IDLESTATE_NAME
] = "name",
174 static char *cpuidle_state_get_one_string(unsigned int cpu
,
175 unsigned int idlestate
,
176 enum idlestate_string which
)
178 char linebuf
[MAX_LINE_LEN
];
182 if (which
>= MAX_IDLESTATE_STRING_FILES
)
185 len
= cpuidle_state_read_file(cpu
, idlestate
,
186 idlestate_string_files
[which
],
187 linebuf
, sizeof(linebuf
));
191 result
= strdup(linebuf
);
195 if (result
[strlen(result
) - 1] == '\n')
196 result
[strlen(result
) - 1] = '\0';
205 * -1 if idlestate is not available
206 * -2 if disabling is not supported by the kernel
208 int cpuidle_is_state_disabled(unsigned int cpu
,
209 unsigned int idlestate
)
211 if (cpuidle_state_count(cpu
) <= idlestate
)
214 if (!cpuidle_state_file_exists(cpu
, idlestate
,
215 idlestate_value_files
[IDLESTATE_DISABLE
]))
217 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_DISABLE
);
221 * Pass 1 as last argument to disable or 0 to enable the state
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
229 int cpuidle_state_disable(unsigned int cpu
,
230 unsigned int idlestate
,
231 unsigned int disable
)
233 char value
[SYSFS_PATH_MAX
];
236 if (cpuidle_state_count(cpu
) <= idlestate
)
239 if (!cpuidle_state_file_exists(cpu
, idlestate
,
240 idlestate_value_files
[IDLESTATE_DISABLE
]))
243 snprintf(value
, SYSFS_PATH_MAX
, "%u", disable
);
245 bytes_written
= cpuidle_state_write_file(cpu
, idlestate
, "disable",
246 value
, sizeof(disable
));
252 unsigned long cpuidle_state_latency(unsigned int cpu
,
253 unsigned int idlestate
)
255 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_LATENCY
);
258 unsigned long cpuidle_state_usage(unsigned int cpu
,
259 unsigned int idlestate
)
261 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_USAGE
);
264 unsigned long long cpuidle_state_time(unsigned int cpu
,
265 unsigned int idlestate
)
267 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_TIME
);
270 char *cpuidle_state_name(unsigned int cpu
, unsigned int idlestate
)
272 return cpuidle_state_get_one_string(cpu
, idlestate
, IDLESTATE_NAME
);
275 char *cpuidle_state_desc(unsigned int cpu
, unsigned int idlestate
)
277 return cpuidle_state_get_one_string(cpu
, idlestate
, IDLESTATE_DESC
);
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
285 unsigned int cpuidle_state_count(unsigned int cpu
)
287 char file
[SYSFS_PATH_MAX
];
292 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpuidle");
293 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
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
))
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
);
309 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
312 * helper function to read file from /sys into given buffer
313 * fname is a relative path under "cpu/cpuidle/" dir
315 static unsigned int sysfs_cpuidle_read_file(const char *fname
, char *buf
,
318 char path
[SYSFS_PATH_MAX
];
320 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpuidle/%s", fname
);
322 return sysfs_read_file(path
, buf
, buflen
);
327 /* read access to files which contain one string */
329 enum cpuidle_string
{
333 MAX_CPUIDLE_STRING_FILES
336 static 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",
343 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which
)
345 char linebuf
[MAX_LINE_LEN
];
349 if (which
>= MAX_CPUIDLE_STRING_FILES
)
352 len
= sysfs_cpuidle_read_file(cpuidle_string_files
[which
],
353 linebuf
, sizeof(linebuf
));
357 result
= strdup(linebuf
);
361 if (result
[strlen(result
) - 1] == '\n')
362 result
[strlen(result
) - 1] = '\0';
367 char *cpuidle_get_governor(void)
369 char *tmp
= sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO
);
371 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR
);
376 char *cpuidle_get_driver(void)
378 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER
);
380 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */