1 // SPDX-License-Identifier: GPL-2.0-only
3 * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
4 * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
11 #include <sys/types.h>
16 #include "helpers/sysfs.h"
18 unsigned int sysfs_read_file(const char *path
, char *buf
, size_t buflen
)
23 fd
= open(path
, O_RDONLY
);
27 numread
= read(fd
, buf
, buflen
- 1);
36 return (unsigned int) numread
;
40 * Detect whether a CPU is online
43 * 1 -> if CPU is online
44 * 0 -> if CPU is offline
45 * negative errno values in error case
47 int sysfs_is_cpu_online(unsigned int cpu
)
49 char path
[SYSFS_PATH_MAX
];
52 unsigned long long value
;
53 char linebuf
[MAX_LINE_LEN
];
57 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u", cpu
);
59 if (stat(path
, &statbuf
) != 0)
63 * kernel without CONFIG_HOTPLUG_CPU
64 * -> cpuX directory exists, but not cpuX/online file
66 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/online", cpu
);
67 if (stat(path
, &statbuf
) != 0)
70 fd
= open(path
, O_RDONLY
);
74 numread
= read(fd
, linebuf
, MAX_LINE_LEN
- 1);
79 linebuf
[numread
] = '\0';
82 value
= strtoull(linebuf
, &endp
, 0);
89 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
92 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
95 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
97 * For example the functionality to disable c-states was introduced in later
98 * kernel versions, this function can be used to explicitly check for this
101 * returns 1 if the file exists, 0 otherwise.
103 unsigned int sysfs_idlestate_file_exists(unsigned int cpu
,
104 unsigned int idlestate
,
107 char path
[SYSFS_PATH_MAX
];
111 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
112 cpu
, idlestate
, fname
);
113 if (stat(path
, &statbuf
) != 0)
119 * helper function to read file from /sys into given buffer
120 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
121 * cstates starting with 0, C0 is not counted as cstate.
122 * This means if you want C1 info, pass 0 as idlestate param
124 unsigned int sysfs_idlestate_read_file(unsigned int cpu
, unsigned int idlestate
,
125 const char *fname
, char *buf
, size_t buflen
)
127 char path
[SYSFS_PATH_MAX
];
131 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
132 cpu
, idlestate
, fname
);
134 fd
= open(path
, O_RDONLY
);
138 numread
= read(fd
, buf
, buflen
- 1);
147 return (unsigned int) numread
;
151 * helper function to write a new value to a /sys file
152 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
154 * Returns the number of bytes written or 0 on error
157 unsigned int sysfs_idlestate_write_file(unsigned int cpu
,
158 unsigned int idlestate
,
160 const char *value
, size_t len
)
162 char path
[SYSFS_PATH_MAX
];
166 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
167 cpu
, idlestate
, fname
);
169 fd
= open(path
, O_WRONLY
);
173 numwrite
= write(fd
, value
, len
);
181 return (unsigned int) numwrite
;
184 /* read access to files which contain one numeric value */
186 enum idlestate_value
{
192 MAX_IDLESTATE_VALUE_FILES
195 static const char *idlestate_value_files
[MAX_IDLESTATE_VALUE_FILES
] = {
196 [IDLESTATE_USAGE
] = "usage",
197 [IDLESTATE_POWER
] = "power",
198 [IDLESTATE_LATENCY
] = "latency",
199 [IDLESTATE_TIME
] = "time",
200 [IDLESTATE_DISABLE
] = "disable",
203 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu
,
204 unsigned int idlestate
,
205 enum idlestate_value which
)
207 unsigned long long value
;
209 char linebuf
[MAX_LINE_LEN
];
212 if (which
>= MAX_IDLESTATE_VALUE_FILES
)
215 len
= sysfs_idlestate_read_file(cpu
, idlestate
,
216 idlestate_value_files
[which
],
217 linebuf
, sizeof(linebuf
));
221 value
= strtoull(linebuf
, &endp
, 0);
223 if (endp
== linebuf
|| errno
== ERANGE
)
229 /* read access to files which contain one string */
231 enum idlestate_string
{
234 MAX_IDLESTATE_STRING_FILES
237 static const char *idlestate_string_files
[MAX_IDLESTATE_STRING_FILES
] = {
238 [IDLESTATE_DESC
] = "desc",
239 [IDLESTATE_NAME
] = "name",
243 static char *sysfs_idlestate_get_one_string(unsigned int cpu
,
244 unsigned int idlestate
,
245 enum idlestate_string which
)
247 char linebuf
[MAX_LINE_LEN
];
251 if (which
>= MAX_IDLESTATE_STRING_FILES
)
254 len
= sysfs_idlestate_read_file(cpu
, idlestate
,
255 idlestate_string_files
[which
],
256 linebuf
, sizeof(linebuf
));
260 result
= strdup(linebuf
);
264 if (result
[strlen(result
) - 1] == '\n')
265 result
[strlen(result
) - 1] = '\0';
274 * -1 if idlestate is not available
275 * -2 if disabling is not supported by the kernel
277 int sysfs_is_idlestate_disabled(unsigned int cpu
,
278 unsigned int idlestate
)
280 if (sysfs_get_idlestate_count(cpu
) <= idlestate
)
283 if (!sysfs_idlestate_file_exists(cpu
, idlestate
,
284 idlestate_value_files
[IDLESTATE_DISABLE
]))
286 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_DISABLE
);
290 * Pass 1 as last argument to disable or 0 to enable the state
293 * negative values on error, for example:
294 * -1 if idlestate is not available
295 * -2 if disabling is not supported by the kernel
296 * -3 No write access to disable/enable C-states
298 int sysfs_idlestate_disable(unsigned int cpu
,
299 unsigned int idlestate
,
300 unsigned int disable
)
302 char value
[SYSFS_PATH_MAX
];
305 if (sysfs_get_idlestate_count(cpu
) <= idlestate
)
308 if (!sysfs_idlestate_file_exists(cpu
, idlestate
,
309 idlestate_value_files
[IDLESTATE_DISABLE
]))
312 snprintf(value
, SYSFS_PATH_MAX
, "%u", disable
);
314 bytes_written
= sysfs_idlestate_write_file(cpu
, idlestate
, "disable",
315 value
, sizeof(disable
));
321 unsigned long sysfs_get_idlestate_latency(unsigned int cpu
,
322 unsigned int idlestate
)
324 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_LATENCY
);
327 unsigned long sysfs_get_idlestate_usage(unsigned int cpu
,
328 unsigned int idlestate
)
330 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_USAGE
);
333 unsigned long long sysfs_get_idlestate_time(unsigned int cpu
,
334 unsigned int idlestate
)
336 return sysfs_idlestate_get_one_value(cpu
, idlestate
, IDLESTATE_TIME
);
339 char *sysfs_get_idlestate_name(unsigned int cpu
, unsigned int idlestate
)
341 return sysfs_idlestate_get_one_string(cpu
, idlestate
, IDLESTATE_NAME
);
344 char *sysfs_get_idlestate_desc(unsigned int cpu
, unsigned int idlestate
)
346 return sysfs_idlestate_get_one_string(cpu
, idlestate
, IDLESTATE_DESC
);
350 * Returns number of supported C-states of CPU core cpu
351 * Negativ in error case
352 * Zero if cpuidle does not export any C-states
354 unsigned int sysfs_get_idlestate_count(unsigned int cpu
)
356 char file
[SYSFS_PATH_MAX
];
361 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpuidle");
362 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
365 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpu%u/cpuidle/state0", cpu
);
366 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
369 while (stat(file
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
370 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
371 "cpu%u/cpuidle/state%d", cpu
, idlestates
);
378 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
381 * helper function to read file from /sys into given buffer
382 * fname is a relative path under "cpu/cpuidle/" dir
384 static unsigned int sysfs_cpuidle_read_file(const char *fname
, char *buf
,
387 char path
[SYSFS_PATH_MAX
];
389 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpuidle/%s", fname
);
391 return sysfs_read_file(path
, buf
, buflen
);
396 /* read access to files which contain one string */
398 enum cpuidle_string
{
402 MAX_CPUIDLE_STRING_FILES
405 static const char *cpuidle_string_files
[MAX_CPUIDLE_STRING_FILES
] = {
406 [CPUIDLE_GOVERNOR
] = "current_governor",
407 [CPUIDLE_GOVERNOR_RO
] = "current_governor_ro",
408 [CPUIDLE_DRIVER
] = "current_driver",
412 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which
)
414 char linebuf
[MAX_LINE_LEN
];
418 if (which
>= MAX_CPUIDLE_STRING_FILES
)
421 len
= sysfs_cpuidle_read_file(cpuidle_string_files
[which
],
422 linebuf
, sizeof(linebuf
));
426 result
= strdup(linebuf
);
430 if (result
[strlen(result
) - 1] == '\n')
431 result
[strlen(result
) - 1] = '\0';
436 char *sysfs_get_cpuidle_governor(void)
438 char *tmp
= sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO
);
440 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR
);
445 char *sysfs_get_cpuidle_driver(void)
447 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER
);
449 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
452 * Get sched_mc or sched_smt settings
453 * Pass "mc" or "smt" as argument
455 * Returns negative value on failure
457 int sysfs_get_sched(const char *smt_mc
)
463 * Get sched_mc or sched_smt settings
464 * Pass "mc" or "smt" as argument
466 * Returns negative value on failure
468 int sysfs_set_sched(const char *smt_mc
, int val
)