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>
17 #include "cpupower_intern.h"
20 * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
22 * For example the functionality to disable c-states was introduced in later
23 * kernel versions, this function can be used to explicitly check for this
26 * returns 1 if the file exists, 0 otherwise.
29 unsigned int cpuidle_state_file_exists(unsigned int cpu
,
30 unsigned int idlestate
,
33 char path
[SYSFS_PATH_MAX
];
37 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
38 cpu
, idlestate
, fname
);
39 if (stat(path
, &statbuf
) != 0)
45 * helper function to read file from /sys into given buffer
46 * fname is a relative path under "cpuX/cpuidle/stateX/" dir
47 * cstates starting with 0, C0 is not counted as cstate.
48 * This means if you want C1 info, pass 0 as idlestate param
51 unsigned int cpuidle_state_read_file(unsigned int cpu
,
52 unsigned int idlestate
,
53 const char *fname
, char *buf
,
56 char path
[SYSFS_PATH_MAX
];
60 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
61 cpu
, idlestate
, fname
);
63 fd
= open(path
, O_RDONLY
);
67 numread
= read(fd
, buf
, buflen
- 1);
76 return (unsigned int) numread
;
80 * helper function to write a new value to a /sys file
81 * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
83 * Returns the number of bytes written or 0 on error
86 unsigned int cpuidle_state_write_file(unsigned int cpu
,
87 unsigned int idlestate
,
89 const char *value
, size_t len
)
91 char path
[SYSFS_PATH_MAX
];
95 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpu%u/cpuidle/state%u/%s",
96 cpu
, idlestate
, fname
);
98 fd
= open(path
, O_WRONLY
);
102 numwrite
= write(fd
, value
, len
);
110 return (unsigned int) numwrite
;
113 /* read access to files which contain one numeric value */
115 enum idlestate_value
{
121 MAX_IDLESTATE_VALUE_FILES
124 static const char *idlestate_value_files
[MAX_IDLESTATE_VALUE_FILES
] = {
125 [IDLESTATE_USAGE
] = "usage",
126 [IDLESTATE_POWER
] = "power",
127 [IDLESTATE_LATENCY
] = "latency",
128 [IDLESTATE_TIME
] = "time",
129 [IDLESTATE_DISABLE
] = "disable",
133 unsigned long long cpuidle_state_get_one_value(unsigned int cpu
,
134 unsigned int idlestate
,
135 enum idlestate_value which
)
137 unsigned long long value
;
139 char linebuf
[MAX_LINE_LEN
];
142 if (which
>= MAX_IDLESTATE_VALUE_FILES
)
145 len
= cpuidle_state_read_file(cpu
, idlestate
,
146 idlestate_value_files
[which
],
147 linebuf
, sizeof(linebuf
));
151 value
= strtoull(linebuf
, &endp
, 0);
153 if (endp
== linebuf
|| errno
== ERANGE
)
159 /* read access to files which contain one string */
161 enum idlestate_string
{
164 MAX_IDLESTATE_STRING_FILES
167 static const char *idlestate_string_files
[MAX_IDLESTATE_STRING_FILES
] = {
168 [IDLESTATE_DESC
] = "desc",
169 [IDLESTATE_NAME
] = "name",
173 static char *cpuidle_state_get_one_string(unsigned int cpu
,
174 unsigned int idlestate
,
175 enum idlestate_string which
)
177 char linebuf
[MAX_LINE_LEN
];
181 if (which
>= MAX_IDLESTATE_STRING_FILES
)
184 len
= cpuidle_state_read_file(cpu
, idlestate
,
185 idlestate_string_files
[which
],
186 linebuf
, sizeof(linebuf
));
190 result
= strdup(linebuf
);
194 if (result
[strlen(result
) - 1] == '\n')
195 result
[strlen(result
) - 1] = '\0';
204 * -1 if idlestate is not available
205 * -2 if disabling is not supported by the kernel
207 int cpuidle_is_state_disabled(unsigned int cpu
,
208 unsigned int idlestate
)
210 if (cpuidle_state_count(cpu
) <= idlestate
)
213 if (!cpuidle_state_file_exists(cpu
, idlestate
,
214 idlestate_value_files
[IDLESTATE_DISABLE
]))
216 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_DISABLE
);
220 * Pass 1 as last argument to disable or 0 to enable the state
223 * negative values on error, for example:
224 * -1 if idlestate is not available
225 * -2 if disabling is not supported by the kernel
226 * -3 No write access to disable/enable C-states
228 int cpuidle_state_disable(unsigned int cpu
,
229 unsigned int idlestate
,
230 unsigned int disable
)
232 char value
[SYSFS_PATH_MAX
];
235 if (cpuidle_state_count(cpu
) <= idlestate
)
238 if (!cpuidle_state_file_exists(cpu
, idlestate
,
239 idlestate_value_files
[IDLESTATE_DISABLE
]))
242 snprintf(value
, SYSFS_PATH_MAX
, "%u", disable
);
244 bytes_written
= cpuidle_state_write_file(cpu
, idlestate
, "disable",
245 value
, sizeof(disable
));
251 unsigned long cpuidle_state_latency(unsigned int cpu
,
252 unsigned int idlestate
)
254 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_LATENCY
);
257 unsigned long cpuidle_state_usage(unsigned int cpu
,
258 unsigned int idlestate
)
260 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_USAGE
);
263 unsigned long long cpuidle_state_time(unsigned int cpu
,
264 unsigned int idlestate
)
266 return cpuidle_state_get_one_value(cpu
, idlestate
, IDLESTATE_TIME
);
269 char *cpuidle_state_name(unsigned int cpu
, unsigned int idlestate
)
271 return cpuidle_state_get_one_string(cpu
, idlestate
, IDLESTATE_NAME
);
274 char *cpuidle_state_desc(unsigned int cpu
, unsigned int idlestate
)
276 return cpuidle_state_get_one_string(cpu
, idlestate
, IDLESTATE_DESC
);
280 * Returns number of supported C-states of CPU core cpu
281 * Negativ in error case
282 * Zero if cpuidle does not export any C-states
284 unsigned int cpuidle_state_count(unsigned int cpu
)
286 char file
[SYSFS_PATH_MAX
];
291 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpuidle");
292 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
295 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
"cpu%u/cpuidle/state0", cpu
);
296 if (stat(file
, &statbuf
) != 0 || !S_ISDIR(statbuf
.st_mode
))
299 while (stat(file
, &statbuf
) == 0 && S_ISDIR(statbuf
.st_mode
)) {
300 snprintf(file
, SYSFS_PATH_MAX
, PATH_TO_CPU
301 "cpu%u/cpuidle/state%d", cpu
, idlestates
);
308 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
311 * helper function to read file from /sys into given buffer
312 * fname is a relative path under "cpu/cpuidle/" dir
314 static unsigned int sysfs_cpuidle_read_file(const char *fname
, char *buf
,
317 char path
[SYSFS_PATH_MAX
];
319 snprintf(path
, sizeof(path
), PATH_TO_CPU
"cpuidle/%s", fname
);
321 return cpupower_read_sysfs(path
, buf
, buflen
);
326 /* read access to files which contain one string */
328 enum cpuidle_string
{
332 MAX_CPUIDLE_STRING_FILES
335 static const char *cpuidle_string_files
[MAX_CPUIDLE_STRING_FILES
] = {
336 [CPUIDLE_GOVERNOR
] = "current_governor",
337 [CPUIDLE_GOVERNOR_RO
] = "current_governor_ro",
338 [CPUIDLE_DRIVER
] = "current_driver",
342 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which
)
344 char linebuf
[MAX_LINE_LEN
];
348 if (which
>= MAX_CPUIDLE_STRING_FILES
)
351 len
= sysfs_cpuidle_read_file(cpuidle_string_files
[which
],
352 linebuf
, sizeof(linebuf
));
356 result
= strdup(linebuf
);
360 if (result
[strlen(result
) - 1] == '\n')
361 result
[strlen(result
) - 1] = '\0';
366 char *cpuidle_get_governor(void)
368 char *tmp
= sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO
);
370 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR
);
375 char *cpuidle_get_driver(void)
377 return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER
);
379 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */