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)