~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/tools/power/cpupower/lib/cpuidle.c

Version: ~ [ linux-6.11.5 ] ~ [ linux-6.10.14 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.58 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.114 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.169 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.228 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.284 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.322 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  1 // SPDX-License-Identifier: GPL-2.0-only
  2 /*
  3  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
  4  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
  5  */
  6 
  7 #include <stdio.h>
  8 #include <errno.h>
  9 #include <stdlib.h>
 10 #include <string.h>
 11 #include <sys/types.h>
 12 #include <sys/stat.h>
 13 #include <fcntl.h>
 14 #include <unistd.h>
 15 
 16 #include "cpuidle.h"
 17 #include "cpupower_intern.h"
 18 
 19 /*
 20  * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
 21  * exists.
 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
 24  * feature.
 25  *
 26  * returns 1 if the file exists, 0 otherwise.
 27  */
 28 static
 29 unsigned int cpuidle_state_file_exists(unsigned int cpu,
 30                                        unsigned int idlestate,
 31                                        const char *fname)
 32 {
 33         char path[SYSFS_PATH_MAX];
 34         struct stat statbuf;
 35 
 36 
 37         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 38                  cpu, idlestate, fname);
 39         if (stat(path, &statbuf) != 0)
 40                 return 0;
 41         return 1;
 42 }
 43 
 44 /*
 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
 49  */
 50 static
 51 unsigned int cpuidle_state_read_file(unsigned int cpu,
 52                                             unsigned int idlestate,
 53                                             const char *fname, char *buf,
 54                                             size_t buflen)
 55 {
 56         char path[SYSFS_PATH_MAX];
 57         int fd;
 58         ssize_t numread;
 59 
 60         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 61                  cpu, idlestate, fname);
 62 
 63         fd = open(path, O_RDONLY);
 64         if (fd == -1)
 65                 return 0;
 66 
 67         numread = read(fd, buf, buflen - 1);
 68         if (numread < 1) {
 69                 close(fd);
 70                 return 0;
 71         }
 72 
 73         buf[numread] = '\0';
 74         close(fd);
 75 
 76         return (unsigned int) numread;
 77 }
 78 
 79 /*
 80  * helper function to write a new value to a /sys file
 81  * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
 82  *
 83  * Returns the number of bytes written or 0 on error
 84  */
 85 static
 86 unsigned int cpuidle_state_write_file(unsigned int cpu,
 87                                       unsigned int idlestate,
 88                                       const char *fname,
 89                                       const char *value, size_t len)
 90 {
 91         char path[SYSFS_PATH_MAX];
 92         int fd;
 93         ssize_t numwrite;
 94 
 95         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
 96                  cpu, idlestate, fname);
 97 
 98         fd = open(path, O_WRONLY);
 99         if (fd == -1)
100                 return 0;
101 
102         numwrite = write(fd, value, len);
103         if (numwrite < 1) {
104                 close(fd);
105                 return 0;
106         }
107 
108         close(fd);
109 
110         return (unsigned int) numwrite;
111 }
112 
113 /* read access to files which contain one numeric value */
114 
115 enum idlestate_value {
116         IDLESTATE_USAGE,
117         IDLESTATE_POWER,
118         IDLESTATE_LATENCY,
119         IDLESTATE_TIME,
120         IDLESTATE_DISABLE,
121         MAX_IDLESTATE_VALUE_FILES
122 };
123 
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",
130 };
131 
132 static
133 unsigned long long cpuidle_state_get_one_value(unsigned int cpu,
134                                                unsigned int idlestate,
135                                                enum idlestate_value which)
136 {
137         unsigned long long value;
138         unsigned int len;
139         char linebuf[MAX_LINE_LEN];
140         char *endp;
141 
142         if (which >= MAX_IDLESTATE_VALUE_FILES)
143                 return 0;
144 
145         len = cpuidle_state_read_file(cpu, idlestate,
146                                       idlestate_value_files[which],
147                                       linebuf, sizeof(linebuf));
148         if (len == 0)
149                 return 0;
150 
151         value = strtoull(linebuf, &endp, 0);
152 
153         if (endp == linebuf || errno == ERANGE)
154                 return 0;
155 
156         return value;
157 }
158 
159 /* read access to files which contain one string */
160 
161 enum idlestate_string {
162         IDLESTATE_DESC,
163         IDLESTATE_NAME,
164         MAX_IDLESTATE_STRING_FILES
165 };
166 
167 static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
168         [IDLESTATE_DESC] = "desc",
169         [IDLESTATE_NAME] = "name",
170 };
171 
172 
173 static char *cpuidle_state_get_one_string(unsigned int cpu,
174                                         unsigned int idlestate,
175                                         enum idlestate_string which)
176 {
177         char linebuf[MAX_LINE_LEN];
178         char *result;
179         unsigned int len;
180 
181         if (which >= MAX_IDLESTATE_STRING_FILES)
182                 return NULL;
183 
184         len = cpuidle_state_read_file(cpu, idlestate,
185                                       idlestate_string_files[which],
186                                       linebuf, sizeof(linebuf));
187         if (len == 0)
188                 return NULL;
189 
190         result = strdup(linebuf);
191         if (result == NULL)
192                 return NULL;
193 
194         if (result[strlen(result) - 1] == '\n')
195                 result[strlen(result) - 1] = '\0';
196 
197         return result;
198 }
199 
200 /*
201  * Returns:
202  *    1  if disabled
203  *    0  if enabled
204  *    -1 if idlestate is not available
205  *    -2 if disabling is not supported by the kernel
206  */
207 int cpuidle_is_state_disabled(unsigned int cpu,
208                                 unsigned int idlestate)
209 {
210         if (cpuidle_state_count(cpu) <= idlestate)
211                 return -1;
212 
213         if (!cpuidle_state_file_exists(cpu, idlestate,
214                                  idlestate_value_files[IDLESTATE_DISABLE]))
215                 return -2;
216         return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
217 }
218 
219 /*
220  * Pass 1 as last argument to disable or 0 to enable the state
221  * Returns:
222  *    0  on success
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
227  */
228 int cpuidle_state_disable(unsigned int cpu,
229                             unsigned int idlestate,
230                             unsigned int disable)
231 {
232         char value[SYSFS_PATH_MAX];
233         int bytes_written;
234 
235         if (cpuidle_state_count(cpu) <= idlestate)
236                 return -1;
237 
238         if (!cpuidle_state_file_exists(cpu, idlestate,
239                                  idlestate_value_files[IDLESTATE_DISABLE]))
240                 return -2;
241 
242         snprintf(value, SYSFS_PATH_MAX, "%u", disable);
243 
244         bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable",
245                                                    value, sizeof(disable));
246         if (bytes_written)
247                 return 0;
248         return -3;
249 }
250 
251 unsigned long cpuidle_state_latency(unsigned int cpu,
252                                           unsigned int idlestate)
253 {
254         return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
255 }
256 
257 unsigned long cpuidle_state_usage(unsigned int cpu,
258                                         unsigned int idlestate)
259 {
260         return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
261 }
262 
263 unsigned long long cpuidle_state_time(unsigned int cpu,
264                                         unsigned int idlestate)
265 {
266         return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME);
267 }
268 
269 char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate)
270 {
271         return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME);
272 }
273 
274 char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate)
275 {
276         return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC);
277 }
278 
279 /*
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
283  */
284 unsigned int cpuidle_state_count(unsigned int cpu)
285 {
286         char file[SYSFS_PATH_MAX];
287         struct stat statbuf;
288         int idlestates = 1;
289 
290 
291         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
292         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
293                 return 0;
294 
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))
297                 return 0;
298 
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);
302                 idlestates++;
303         }
304         idlestates--;
305         return idlestates;
306 }
307 
308 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
309 
310 /*
311  * helper function to read file from /sys into given buffer
312  * fname is a relative path under "cpu/cpuidle/" dir
313  */
314 static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
315                                             size_t buflen)
316 {
317         char path[SYSFS_PATH_MAX];
318 
319         snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
320 
321         return cpupower_read_sysfs(path, buf, buflen);
322 }
323 
324 
325 
326 /* read access to files which contain one string */
327 
328 enum cpuidle_string {
329         CPUIDLE_GOVERNOR,
330         CPUIDLE_GOVERNOR_RO,
331         CPUIDLE_DRIVER,
332         MAX_CPUIDLE_STRING_FILES
333 };
334 
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",
339 };
340 
341 
342 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
343 {
344         char linebuf[MAX_LINE_LEN];
345         char *result;
346         unsigned int len;
347 
348         if (which >= MAX_CPUIDLE_STRING_FILES)
349                 return NULL;
350 
351         len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
352                                 linebuf, sizeof(linebuf));
353         if (len == 0)
354                 return NULL;
355 
356         result = strdup(linebuf);
357         if (result == NULL)
358                 return NULL;
359 
360         if (result[strlen(result) - 1] == '\n')
361                 result[strlen(result) - 1] = '\0';
362 
363         return result;
364 }
365 
366 char *cpuidle_get_governor(void)
367 {
368         char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
369         if (!tmp)
370                 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
371         else
372                 return tmp;
373 }
374 
375 char *cpuidle_get_driver(void)
376 {
377         return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
378 }
379 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
380 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php