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>
17 #include "helpers/sysfs.h"
19 unsigned int sysfs_read_file(const char *path
, char *buf
, size_t buflen
)
24 fd
= open(path
, O_RDONLY
);
28 numread
= read(fd
, buf
, buflen
- 1);
37 return (unsigned int) numread
;
41 * Detect whether a CPU is online
44 * 1 -> if CPU is online
45 * 0 -> if CPU is offline
46 * negative errno values in error case
48 int sysfs_is_cpu_online(unsigned int cpu
)
50 char path
[SYSFS_PATH_MAX
];
53 unsigned long long value
;
54 char linebuf
[MAX_LINE_LEN
];
58 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u", cpu
);
60 if (stat(path
, &statbuf
) != 0)
64 * kernel without CONFIG_HOTPLUG_CPU
65 * -> cpuX directory exists, but not cpuX/online file
67 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/online", cpu
);
68 if (stat(path
, &statbuf
) != 0)
71 fd
= open(path
, O_RDONLY
);
75 numread
= read(fd
, linebuf
, MAX_LINE_LEN
- 1);
80 linebuf
[numread
] = '\0';
83 value
= strtoull(linebuf
, &endp
, 0);
90 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
93 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
96 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
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
102 * returns 1 if the file exists, 0 otherwise.
104 unsigned int sysfs_idlestate_file_exists(unsigned int cpu
,
105 unsigned int idlestate
,
108 char path
[SYSFS_PATH_MAX
];
112 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
113 cpu
, idlestate
, fname
);
114 if (stat(path
, &statbuf
) != 0)
120 * helper function to read file from /sys into given buffer
121 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
122 * cstates starting with 0, C0 is not counted as cstate.
123 * This means if you want C1 info, pass 0 as idlestate param
125 unsigned int sysfs_idlestate_read_file(unsigned int cpu
, unsigned int idlestate
,
126 const char *fname
, char *buf
, size_t buflen
)
128 char path
[SYSFS_PATH_MAX
];
132 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
133 cpu
, idlestate
, fname
);
135 fd
= open(path
, O_RDONLY
);
139 numread
= read(fd
, buf
, buflen
- 1);
148 return (unsigned int) numread
;
152 * helper function to write a new value to a /sys file
153 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
155 * Returns the number of bytes written or 0 on error
158 unsigned int sysfs_idlestate_write_file(unsigned int cpu
,
159 unsigned int idlestate
,
161 const char *value
, size_t len
)
163 char path
[SYSFS_PATH_MAX
];
167 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
168 cpu
, idlestate
, fname
);
170 fd
= open(path
, O_WRONLY
);
174 numwrite
= write(fd
, value
, len
);
182 return (unsigned int) numwrite
;
185 /* read access to files which contain one numeric value */
187 enum idlestate_value
{
193 MAX_IDLESTATE_VALUE_FILES
196 static const char *idlestate_value_files
[MAX_IDLESTATE_VALUE_FILES
] = {
197 [IDLESTATE_USAGE
] = "usage",
198 [IDLESTATE_POWER
] = "power",
199 [IDLESTATE_LATENCY
] = "latency",
200 [IDLESTATE_TIME
] = "time",
201 [IDLESTATE_DISABLE
] = "disable",
204 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu
,
205 unsigned int idlestate
,
206 enum idlestate_value which
)
208 unsigned long long value
;
210 char linebuf
[MAX_LINE_LEN
];
213 if (which
>= MAX_IDLESTATE_VALUE_FILES
)
216 len
= sysfs_idlestate_read_file(cpu
, idlestate
,
217 idlestate_value_files
[which
],
218 linebuf
, sizeof(linebuf
));
222 value
= strtoull(linebuf
, &endp
, 0);
224 if (endp
== linebuf
|| errno
== ERANGE
)
230 /* read access to files which contain one string */
232 enum idlestate_string
{
235 MAX_IDLESTATE_STRING_FILES
238 static const char *idlestate_string_files
[MAX_IDLESTATE_STRING_FILES
] = {
239 [IDLESTATE_DESC
] = "desc",
240 [IDLESTATE_NAME
] = "name",
244 static char *sysfs_idlestate_get_one_string(unsigned int cpu
,
245 unsigned int idlestate
,
246 enum idlestate_string which
)
248 char linebuf
[MAX_LINE_LEN
];
252 if (which
>= MAX_IDLESTATE_STRING_FILES
)
255 len
= sysfs_idlestate_read_file(cpu
, idlestate
,
256 idlestate_string_files
[which
],
257 linebuf
, sizeof(linebuf
));
261 result
= strdup(linebuf
);
265 if (result
[strlen(result
) - 1] == '\n')
266 result
[strlen(result
) - 1] = '\0';
275 * -1 if idlestate is not available
276 * -2 if disabling is not supported by the kernel
278 int sysfs_is_idlestate_disabled(unsigned int cpu
,
279 unsigned int idlestate
)
281 if (sysfs_get_idlestate_count(cpu
) <= idlestate
)
284 if (!sysfs_idlestate_file_exists(cpu
, idlestate
,
285 idlestate_value_files
[IDLESTATE_DISABLE
]))
287 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_DISABLE
);
291 * Pass 1 as last argument to disable or 0 to enable the state
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
299 int sysfs_idlestate_disable(unsigned int cpu
,
300 unsigned int idlestate
,
301 unsigned int disable
)
303 char value
[SYSFS_PATH_MAX
];
306 if (sysfs_get_idlestate_count(cpu
) <= idlestate
)
309 if (!sysfs_idlestate_file_exists(cpu
, idlestate
,
310 idlestate_value_files
[IDLESTATE_DISABLE
]))
313 snprintf(value
, SYSFS_PATH_MAX
, "%u", disable
);
315 bytes_written
= sysfs_idlestate_write_file(cpu
, idlestate
, "disable",
316 value
, sizeof(disable
));
322 unsigned long sysfs_get_idlestate_latency(unsigned int cpu
,
323 unsigned int idlestate
)
325 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_LATENCY
);
328 unsigned long sysfs_get_idlestate_usage(unsigned int cpu
,
329 unsigned int idlestate
)
331 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_USAGE
);
334 unsigned long long sysfs_get_idlestate_time(unsigned int cpu
,
335 unsigned int idlestate
)
337 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_TIME
);
340 char *sysfs_get_idlestate_name(unsigned int cpu
, unsigned int idlestate
)
342 return sysfs_idlestate_get_one_string(cpu
, idlestate
, IDLESTATE_NAME
);
345 char *sysfs_get_idlestate_desc(unsigned int cpu
, unsigned int idlestate
)
347 return sysfs_idlestate_get_one_string(cpu
, idlestate
, IDLESTATE_DESC
);
351 * Returns number of supported C-states of CPU core cpu
352 * Negativ in error case
353 * Zero if cpuidle does not export any C-states
355 unsigned int sysfs_get_idlestate_count(unsigned int cpu
)
357 char file
[SYSFS_PATH_MAX
];
362 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpuidle");
363 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
366 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpu%u/cpuidle/state0", cpu
);
367 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
370 while (stat(file
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
371 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
372 "cpu%u/cpuidle/state%d", cpu
, idlestates
);
379 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
382 * helper function to read file from /sys into given buffer
383 * fname is a relative path under "cpu/cpuidle/" dir
385 static unsigned int sysfs_cpuidle_read_file(const char *fname
, char *buf
,
388 char path
[SYSFS_PATH_MAX
];
390 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpuidle/%s", fname
);
392 return sysfs_read_file(path
, buf
, buflen
);
397 /* read access to files which contain one string */
399 enum cpuidle_string
{
403 MAX_CPUIDLE_STRING_FILES
406 static const char *cpuidle_string_files
[MAX_CPUIDLE_STRING_FILES
] = {
407 [CPUIDLE_GOVERNOR
] = "current_governor",
408 [CPUIDLE_GOVERNOR_RO
] = "current_governor_ro",
409 [CPUIDLE_DRIVER
] = "current_driver",
413 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which
)
415 char linebuf
[MAX_LINE_LEN
];
419 if (which
>= MAX_CPUIDLE_STRING_FILES
)
422 len
= sysfs_cpuidle_read_file(cpuidle_string_files
[which
],
423 linebuf
, sizeof(linebuf
));
427 result
= strdup(linebuf
);
431 if (result
[strlen(result
) - 1] == '\n')
432 result
[strlen(result
) - 1] = '\0';
437 char *sysfs_get_cpuidle_governor(void)
439 char *tmp
= sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO
);
441 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR
);
446 char *sysfs_get_cpuidle_driver(void)
448 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER
);
450 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
453 * Get sched_mc or sched_smt settings
454 * Pass "mc" or "smt" as argument
456 * Returns negative value on failure
458 int sysfs_get_sched(const char *smt_mc
)
464 * Get sched_mc or sched_smt settings
465 * Pass "mc" or "smt" as argument
467 * Returns negative value on failure
469 int sysfs_set_sched(const char *smt_mc
, int val
)