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;
40
static unsigned int sysfs_write_file(const char *path,
41
const char *value, size_t len)
46
fd = open(path, O_WRONLY);
50
numwrite = write(fd, value, len);
56
return (unsigned int) numwrite;
60
* Detect whether a CPU is online
63
* 1 -> if CPU is online
64
* 0 -> if CPU is offline
65
* negative errno values in error case
67
int sysfs_is_cpu_online(unsigned int cpu)
69
char path[SYSFS_PATH_MAX];
72
unsigned long long value;
73
char linebuf[MAX_LINE_LEN];
77
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
79
if (stat(path, &statbuf) != 0)
83
* kernel without CONFIG_HOTPLUG_CPU
84
* -> cpuX directory exists, but not cpuX/online file
86
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
87
if (stat(path, &statbuf) != 0)
90
fd = open(path, O_RDONLY);
94
numread = read(fd, linebuf, MAX_LINE_LEN - 1);
99
linebuf[numread] = '\0';
102
value = strtoull(linebuf, &endp, 0);
103
if (value > 1 || value < 0)
109
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
112
* helper function to read file from /sys into given buffer
113
* fname is a relative path under "cpuX/cpuidle/stateX/" dir
114
* cstates starting with 0, C0 is not counted as cstate.
115
* This means if you want C1 info, pass 0 as idlestate param
117
unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
118
const char *fname, char *buf, size_t buflen)
120
char path[SYSFS_PATH_MAX];
124
snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
125
cpu, idlestate, fname);
127
fd = open(path, O_RDONLY);
131
numread = read(fd, buf, buflen - 1);
140
return (unsigned int) numread;
143
/* read access to files which contain one numeric value */
145
enum idlestate_value {
150
MAX_IDLESTATE_VALUE_FILES
153
static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
154
[IDLESTATE_USAGE] = "usage",
155
[IDLESTATE_POWER] = "power",
156
[IDLESTATE_LATENCY] = "latency",
157
[IDLESTATE_TIME] = "time",
160
static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
161
unsigned int idlestate,
162
enum idlestate_value which)
164
unsigned long long value;
166
char linebuf[MAX_LINE_LEN];
169
if (which >= MAX_IDLESTATE_VALUE_FILES)
172
len = sysfs_idlestate_read_file(cpu, idlestate,
173
idlestate_value_files[which],
174
linebuf, sizeof(linebuf));
178
value = strtoull(linebuf, &endp, 0);
180
if (endp == linebuf || errno == ERANGE)
186
/* read access to files which contain one string */
188
enum idlestate_string {
191
MAX_IDLESTATE_STRING_FILES
194
static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
195
[IDLESTATE_DESC] = "desc",
196
[IDLESTATE_NAME] = "name",
200
static char *sysfs_idlestate_get_one_string(unsigned int cpu,
201
unsigned int idlestate,
202
enum idlestate_string which)
204
char linebuf[MAX_LINE_LEN];
208
if (which >= MAX_IDLESTATE_STRING_FILES)
211
len = sysfs_idlestate_read_file(cpu, idlestate,
212
idlestate_string_files[which],
213
linebuf, sizeof(linebuf));
217
result = strdup(linebuf);
221
if (result[strlen(result) - 1] == '\n')
222
result[strlen(result) - 1] = '\0';
227
unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
228
unsigned int idlestate)
230
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
233
unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
234
unsigned int idlestate)
236
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
239
unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
240
unsigned int idlestate)
242
return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
245
char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
247
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
250
char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
252
return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
256
* Returns number of supported C-states of CPU core cpu
257
* Negativ in error case
258
* Zero if cpuidle does not export any C-states
260
int sysfs_get_idlestate_count(unsigned int cpu)
262
char file[SYSFS_PATH_MAX];
267
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
268
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
271
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
272
if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
275
while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
276
snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
277
"cpu%u/cpuidle/state%d", cpu, idlestates);
284
/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
287
* helper function to read file from /sys into given buffer
288
* fname is a relative path under "cpu/cpuidle/" dir
290
static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
293
char path[SYSFS_PATH_MAX];
295
snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
297
return sysfs_read_file(path, buf, buflen);
302
/* read access to files which contain one string */
304
enum cpuidle_string {
308
MAX_CPUIDLE_STRING_FILES
311
static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
312
[CPUIDLE_GOVERNOR] = "current_governor",
313
[CPUIDLE_GOVERNOR_RO] = "current_governor_ro",
314
[CPUIDLE_DRIVER] = "current_driver",
318
static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
320
char linebuf[MAX_LINE_LEN];
324
if (which >= MAX_CPUIDLE_STRING_FILES)
327
len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
328
linebuf, sizeof(linebuf));
332
result = strdup(linebuf);
336
if (result[strlen(result) - 1] == '\n')
337
result[strlen(result) - 1] = '\0';
342
char *sysfs_get_cpuidle_governor(void)
344
char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
346
return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
351
char *sysfs_get_cpuidle_driver(void)
353
return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
355
/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
358
* Get sched_mc or sched_smt settings
359
* Pass "mc" or "smt" as argument
361
* Returns negative value on failure
363
int sysfs_get_sched(const char *smt_mc)
366
char linebuf[MAX_LINE_LEN];
368
char path[SYSFS_PATH_MAX];
370
if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
373
snprintf(path, sizeof(path),
374
PATH_TO_CPU "sched_%s_power_savings", smt_mc);
375
if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
377
value = strtoul(linebuf, &endp, 0);
378
if (endp == linebuf || errno == ERANGE)
384
* Get sched_mc or sched_smt settings
385
* Pass "mc" or "smt" as argument
387
* Returns negative value on failure
389
int sysfs_set_sched(const char *smt_mc, int val)
391
char linebuf[MAX_LINE_LEN];
392
char path[SYSFS_PATH_MAX];
395
if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
398
snprintf(path, sizeof(path),
399
PATH_TO_CPU "sched_%s_power_savings", smt_mc);
400
sprintf(linebuf, "%d", val);
402
if (stat(path, &statbuf) != 0)
405
if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)