Merge remote-tracking branches 'asoc/fix/adsp', 'asoc/fix/arizona', 'asoc/fix/atmel...
[linux-drm-fsl-dcu.git] / tools / power / cpupower / utils / helpers / sysfs.c
1 /*
2  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
3  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
4  *
5  *  Licensed under the terms of the GNU GPL License version 2.
6  */
7
8 #include <stdio.h>
9 #include <errno.h>
10 #include <stdlib.h>
11 #include <string.h>
12 #include <sys/types.h>
13 #include <sys/stat.h>
14 #include <fcntl.h>
15 #include <unistd.h>
16
17 #include "helpers/sysfs.h"
18
19 unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
20 {
21         int fd;
22         ssize_t numread;
23
24         fd = open(path, O_RDONLY);
25         if (fd == -1)
26                 return 0;
27
28         numread = read(fd, buf, buflen - 1);
29         if (numread < 1) {
30                 close(fd);
31                 return 0;
32         }
33
34         buf[numread] = '\0';
35         close(fd);
36
37         return (unsigned int) numread;
38 }
39
40 /*
41  * Detect whether a CPU is online
42  *
43  * Returns:
44  *     1 -> if CPU is online
45  *     0 -> if CPU is offline
46  *     negative errno values in error case
47  */
48 int sysfs_is_cpu_online(unsigned int cpu)
49 {
50         char path[SYSFS_PATH_MAX];
51         int fd;
52         ssize_t numread;
53         unsigned long long value;
54         char linebuf[MAX_LINE_LEN];
55         char *endp;
56         struct stat statbuf;
57
58         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
59
60         if (stat(path, &statbuf) != 0)
61                 return 0;
62
63         /*
64          * kernel without CONFIG_HOTPLUG_CPU
65          * -> cpuX directory exists, but not cpuX/online file
66          */
67         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
68         if (stat(path, &statbuf) != 0)
69                 return 1;
70
71         fd = open(path, O_RDONLY);
72         if (fd == -1)
73                 return -errno;
74
75         numread = read(fd, linebuf, MAX_LINE_LEN - 1);
76         if (numread < 1) {
77                 close(fd);
78                 return -EIO;
79         }
80         linebuf[numread] = '\0';
81         close(fd);
82
83         value = strtoull(linebuf, &endp, 0);
84         if (value > 1 || value < 0)
85                 return -EINVAL;
86
87         return value;
88 }
89
90 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
91
92
93 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
94
95 /*
96  * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
97  * exists.
98  * For example the functionality to disable c-states was introduced in later
99  * kernel versions, this function can be used to explicitly check for this
100  * feature.
101  *
102  * returns 1 if the file exists, 0 otherwise.
103  */
104 unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
105                                          unsigned int idlestate,
106                                          const char *fname)
107 {
108         char path[SYSFS_PATH_MAX];
109         struct stat statbuf;
110
111
112         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
113                  cpu, idlestate, fname);
114         if (stat(path, &statbuf) != 0)
115                 return 0;
116         return 1;
117 }
118
119 /*
120  * helper function to read file from /sys into given buffer
121  * fname is a relative path under "cpuX/cpuidle/stateX/" dir
122  * cstates starting with 0, C0 is not counted as cstate.
123  * This means if you want C1 info, pass 0 as idlestate param
124  */
125 unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
126                              const char *fname, char *buf, size_t buflen)
127 {
128         char path[SYSFS_PATH_MAX];
129         int fd;
130         ssize_t numread;
131
132         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
133                  cpu, idlestate, fname);
134
135         fd = open(path, O_RDONLY);
136         if (fd == -1)
137                 return 0;
138
139         numread = read(fd, buf, buflen - 1);
140         if (numread < 1) {
141                 close(fd);
142                 return 0;
143         }
144
145         buf[numread] = '\0';
146         close(fd);
147
148         return (unsigned int) numread;
149 }
150
151 /* 
152  * helper function to write a new value to a /sys file
153  * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
154  *
155  * Returns the number of bytes written or 0 on error
156  */
157 static
158 unsigned int sysfs_idlestate_write_file(unsigned int cpu,
159                                         unsigned int idlestate,
160                                         const char *fname,
161                                         const char *value, size_t len)
162 {
163         char path[SYSFS_PATH_MAX];
164         int fd;
165         ssize_t numwrite;
166
167         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
168                  cpu, idlestate, fname);
169
170         fd = open(path, O_WRONLY);
171         if (fd == -1)
172                 return 0;
173
174         numwrite = write(fd, value, len);
175         if (numwrite < 1) {
176                 close(fd);
177                 return 0;
178         }
179
180         close(fd);
181
182         return (unsigned int) numwrite;
183 }
184
185 /* read access to files which contain one numeric value */
186
187 enum idlestate_value {
188         IDLESTATE_USAGE,
189         IDLESTATE_POWER,
190         IDLESTATE_LATENCY,
191         IDLESTATE_TIME,
192         IDLESTATE_DISABLE,
193         MAX_IDLESTATE_VALUE_FILES
194 };
195
196 static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
197         [IDLESTATE_USAGE] = "usage",
198         [IDLESTATE_POWER] = "power",
199         [IDLESTATE_LATENCY] = "latency",
200         [IDLESTATE_TIME]  = "time",
201         [IDLESTATE_DISABLE]  = "disable",
202 };
203
204 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
205                                                      unsigned int idlestate,
206                                                      enum idlestate_value which)
207 {
208         unsigned long long value;
209         unsigned int len;
210         char linebuf[MAX_LINE_LEN];
211         char *endp;
212
213         if (which >= MAX_IDLESTATE_VALUE_FILES)
214                 return 0;
215
216         len = sysfs_idlestate_read_file(cpu, idlestate,
217                                         idlestate_value_files[which],
218                                         linebuf, sizeof(linebuf));
219         if (len == 0)
220                 return 0;
221
222         value = strtoull(linebuf, &endp, 0);
223
224         if (endp == linebuf || errno == ERANGE)
225                 return 0;
226
227         return value;
228 }
229
230 /* read access to files which contain one string */
231
232 enum idlestate_string {
233         IDLESTATE_DESC,
234         IDLESTATE_NAME,
235         MAX_IDLESTATE_STRING_FILES
236 };
237
238 static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
239         [IDLESTATE_DESC] = "desc",
240         [IDLESTATE_NAME] = "name",
241 };
242
243
244 static char *sysfs_idlestate_get_one_string(unsigned int cpu,
245                                         unsigned int idlestate,
246                                         enum idlestate_string which)
247 {
248         char linebuf[MAX_LINE_LEN];
249         char *result;
250         unsigned int len;
251
252         if (which >= MAX_IDLESTATE_STRING_FILES)
253                 return NULL;
254
255         len = sysfs_idlestate_read_file(cpu, idlestate,
256                                         idlestate_string_files[which],
257                                         linebuf, sizeof(linebuf));
258         if (len == 0)
259                 return NULL;
260
261         result = strdup(linebuf);
262         if (result == NULL)
263                 return NULL;
264
265         if (result[strlen(result) - 1] == '\n')
266                 result[strlen(result) - 1] = '\0';
267
268         return result;
269 }
270
271 /*
272  * Returns:
273  *    1  if disabled
274  *    0  if enabled
275  *    -1 if idlestate is not available
276  *    -2 if disabling is not supported by the kernel
277  */
278 int sysfs_is_idlestate_disabled(unsigned int cpu,
279                                 unsigned int idlestate)
280 {
281         if (sysfs_get_idlestate_count(cpu) <= idlestate)
282                 return -1;
283
284         if (!sysfs_idlestate_file_exists(cpu, idlestate,
285                                  idlestate_value_files[IDLESTATE_DISABLE]))
286                 return -2;
287         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
288 }
289
290 /*
291  * Pass 1 as last argument to disable or 0 to enable the state
292  * Returns:
293  *    0  on success
294  *    negative values on error, for example:
295  *      -1 if idlestate is not available
296  *      -2 if disabling is not supported by the kernel
297  *      -3 No write access to disable/enable C-states
298  */
299 int sysfs_idlestate_disable(unsigned int cpu,
300                             unsigned int idlestate,
301                             unsigned int disable)
302 {
303         char value[SYSFS_PATH_MAX];
304         int bytes_written;
305
306         if (sysfs_get_idlestate_count(cpu) <= idlestate)
307                 return -1;
308
309         if (!sysfs_idlestate_file_exists(cpu, idlestate,
310                                  idlestate_value_files[IDLESTATE_DISABLE]))
311                 return -2;
312
313         snprintf(value, SYSFS_PATH_MAX, "%u", disable);
314
315         bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
316                                                    value, sizeof(disable));
317         if (bytes_written)
318                 return 0;
319         return -3;
320 }
321
322 unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
323                                           unsigned int idlestate)
324 {
325         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
326 }
327
328 unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
329                                         unsigned int idlestate)
330 {
331         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
332 }
333
334 unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
335                                         unsigned int idlestate)
336 {
337         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
338 }
339
340 char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
341 {
342         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
343 }
344
345 char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
346 {
347         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
348 }
349
350 /*
351  * Returns number of supported C-states of CPU core cpu
352  * Negativ in error case
353  * Zero if cpuidle does not export any C-states
354  */
355 unsigned int sysfs_get_idlestate_count(unsigned int cpu)
356 {
357         char file[SYSFS_PATH_MAX];
358         struct stat statbuf;
359         int idlestates = 1;
360
361
362         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
363         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
364                 return -ENODEV;
365
366         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
367         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
368                 return 0;
369
370         while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
371                 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
372                          "cpu%u/cpuidle/state%d", cpu, idlestates);
373                 idlestates++;
374         }
375         idlestates--;
376         return idlestates;
377 }
378
379 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
380
381 /*
382  * helper function to read file from /sys into given buffer
383  * fname is a relative path under "cpu/cpuidle/" dir
384  */
385 static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
386                                             size_t buflen)
387 {
388         char path[SYSFS_PATH_MAX];
389
390         snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
391
392         return sysfs_read_file(path, buf, buflen);
393 }
394
395
396
397 /* read access to files which contain one string */
398
399 enum cpuidle_string {
400         CPUIDLE_GOVERNOR,
401         CPUIDLE_GOVERNOR_RO,
402         CPUIDLE_DRIVER,
403         MAX_CPUIDLE_STRING_FILES
404 };
405
406 static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
407         [CPUIDLE_GOVERNOR]      = "current_governor",
408         [CPUIDLE_GOVERNOR_RO]   = "current_governor_ro",
409         [CPUIDLE_DRIVER]        = "current_driver",
410 };
411
412
413 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
414 {
415         char linebuf[MAX_LINE_LEN];
416         char *result;
417         unsigned int len;
418
419         if (which >= MAX_CPUIDLE_STRING_FILES)
420                 return NULL;
421
422         len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
423                                 linebuf, sizeof(linebuf));
424         if (len == 0)
425                 return NULL;
426
427         result = strdup(linebuf);
428         if (result == NULL)
429                 return NULL;
430
431         if (result[strlen(result) - 1] == '\n')
432                 result[strlen(result) - 1] = '\0';
433
434         return result;
435 }
436
437 char *sysfs_get_cpuidle_governor(void)
438 {
439         char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
440         if (!tmp)
441                 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
442         else
443                 return tmp;
444 }
445
446 char *sysfs_get_cpuidle_driver(void)
447 {
448         return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
449 }
450 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
451
452 /*
453  * Get sched_mc or sched_smt settings
454  * Pass "mc" or "smt" as argument
455  *
456  * Returns negative value on failure
457  */
458 int sysfs_get_sched(const char *smt_mc)
459 {
460         return -ENODEV;
461 }
462
463 /*
464  * Get sched_mc or sched_smt settings
465  * Pass "mc" or "smt" as argument
466  *
467  * Returns negative value on failure
468  */
469 int sysfs_set_sched(const char *smt_mc, int val)
470 {
471         return -ENODEV;
472 }