cpupowerutils: helpers - ConfigStyle bugfixes
[linux-2.6.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 static unsigned int sysfs_write_file(const char *path,
41                                      const char *value, size_t len)
42 {
43         int fd;
44         ssize_t numwrite;
45
46         fd = open(path, O_WRONLY);
47         if (fd == -1)
48                 return 0;
49
50         numwrite = write(fd, value, len);
51         if (numwrite < 1) {
52                 close(fd);
53                 return 0;
54         }
55         close(fd);
56         return (unsigned int) numwrite;
57 }
58
59 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
60
61 /*
62  * helper function to read file from /sys into given buffer
63  * fname is a relative path under "cpuX/cpuidle/stateX/" dir
64  * cstates starting with 0, C0 is not counted as cstate.
65  * This means if you want C1 info, pass 0 as idlestate param
66  */
67 unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
68                              const char *fname, char *buf, size_t buflen)
69 {
70         char path[SYSFS_PATH_MAX];
71         int fd;
72         ssize_t numread;
73
74         snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
75                  cpu, idlestate, fname);
76
77         fd = open(path, O_RDONLY);
78         if (fd == -1)
79                 return 0;
80
81         numread = read(fd, buf, buflen - 1);
82         if (numread < 1) {
83                 close(fd);
84                 return 0;
85         }
86
87         buf[numread] = '\0';
88         close(fd);
89
90         return (unsigned int) numread;
91 }
92
93 /* read access to files which contain one numeric value */
94
95 enum idlestate_value {
96         IDLESTATE_USAGE,
97         IDLESTATE_POWER,
98         IDLESTATE_LATENCY,
99         IDLESTATE_TIME,
100         MAX_IDLESTATE_VALUE_FILES
101 };
102
103 static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
104         [IDLESTATE_USAGE] = "usage",
105         [IDLESTATE_POWER] = "power",
106         [IDLESTATE_LATENCY] = "latency",
107         [IDLESTATE_TIME]  = "time",
108 };
109
110 static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
111                                                      unsigned int idlestate,
112                                                      enum idlestate_value which)
113 {
114         unsigned long long value;
115         unsigned int len;
116         char linebuf[MAX_LINE_LEN];
117         char *endp;
118
119         if (which >= MAX_IDLESTATE_VALUE_FILES)
120                 return 0;
121
122         len = sysfs_idlestate_read_file(cpu, idlestate,
123                                         idlestate_value_files[which],
124                                         linebuf, sizeof(linebuf));
125         if (len == 0)
126                 return 0;
127
128         value = strtoull(linebuf, &endp, 0);
129
130         if (endp == linebuf || errno == ERANGE)
131                 return 0;
132
133         return value;
134 }
135
136 /* read access to files which contain one string */
137
138 enum idlestate_string {
139         IDLESTATE_DESC,
140         IDLESTATE_NAME,
141         MAX_IDLESTATE_STRING_FILES
142 };
143
144 static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
145         [IDLESTATE_DESC] = "desc",
146         [IDLESTATE_NAME] = "name",
147 };
148
149
150 static char *sysfs_idlestate_get_one_string(unsigned int cpu,
151                                         unsigned int idlestate,
152                                         enum idlestate_string which)
153 {
154         char linebuf[MAX_LINE_LEN];
155         char *result;
156         unsigned int len;
157
158         if (which >= MAX_IDLESTATE_STRING_FILES)
159                 return NULL;
160
161         len = sysfs_idlestate_read_file(cpu, idlestate,
162                                         idlestate_string_files[which],
163                                         linebuf, sizeof(linebuf));
164         if (len == 0)
165                 return NULL;
166
167         result = strdup(linebuf);
168         if (result == NULL)
169                 return NULL;
170
171         if (result[strlen(result) - 1] == '\n')
172                 result[strlen(result) - 1] = '\0';
173
174         return result;
175 }
176
177 unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
178                                         unsigned int idlestate)
179 {
180         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
181 }
182
183 unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
184                                         unsigned int idlestate)
185 {
186         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
187 }
188
189 unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
190                                         unsigned int idlestate)
191 {
192         return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
193 }
194
195 char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
196 {
197         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
198 }
199
200 char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
201 {
202         return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
203 }
204
205 /*
206  * Returns number of supported C-states of CPU core cpu
207  * Negativ in error case
208  * Zero if cpuidle does not export any C-states
209  */
210 int sysfs_get_idlestate_count(unsigned int cpu)
211 {
212         char file[SYSFS_PATH_MAX];
213         struct stat statbuf;
214         int idlestates = 1;
215
216
217         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
218         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
219                 return -ENODEV;
220
221         snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
222         if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
223                 return 0;
224
225         while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
226                 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
227                          "cpu%u/cpuidle/state%d", cpu, idlestates);
228                 idlestates++;
229         }
230         idlestates--;
231         return idlestates;
232 }
233
234 /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
235
236 /*
237  * helper function to read file from /sys into given buffer
238  * fname is a relative path under "cpu/cpuidle/" dir
239  */
240 static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
241                                             size_t buflen)
242 {
243         char path[SYSFS_PATH_MAX];
244
245         snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
246
247         return sysfs_read_file(path, buf, buflen);
248 }
249
250
251
252 /* read access to files which contain one string */
253
254 enum cpuidle_string {
255         CPUIDLE_GOVERNOR,
256         CPUIDLE_GOVERNOR_RO,
257         CPUIDLE_DRIVER,
258         MAX_CPUIDLE_STRING_FILES
259 };
260
261 static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
262         [CPUIDLE_GOVERNOR]      = "current_governor",
263         [CPUIDLE_GOVERNOR_RO]   = "current_governor_ro",
264         [CPUIDLE_DRIVER]        = "current_driver",
265 };
266
267
268 static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
269 {
270         char linebuf[MAX_LINE_LEN];
271         char *result;
272         unsigned int len;
273
274         if (which >= MAX_CPUIDLE_STRING_FILES)
275                 return NULL;
276
277         len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
278                                 linebuf, sizeof(linebuf));
279         if (len == 0)
280                 return NULL;
281
282         result = strdup(linebuf);
283         if (result == NULL)
284                 return NULL;
285
286         if (result[strlen(result) - 1] == '\n')
287                 result[strlen(result) - 1] = '\0';
288
289         return result;
290 }
291
292 char *sysfs_get_cpuidle_governor(void)
293 {
294         char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
295         if (!tmp)
296                 return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
297         else
298                 return tmp;
299 }
300
301 char *sysfs_get_cpuidle_driver(void)
302 {
303         return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
304 }
305 /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
306
307 /*
308  * Get sched_mc or sched_smt settings
309  * Pass "mc" or "smt" as argument
310  *
311  * Returns negative value on failure
312  */
313 int sysfs_get_sched(const char *smt_mc)
314 {
315         unsigned long value;
316         char linebuf[MAX_LINE_LEN];
317         char *endp;
318         char path[SYSFS_PATH_MAX];
319
320         if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
321                 return -EINVAL;
322
323         snprintf(path, sizeof(path),
324                 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
325         if (sysfs_read_file(path, linebuf, MAX_LINE_LEN) == 0)
326                 return -1;
327         value = strtoul(linebuf, &endp, 0);
328         if (endp == linebuf || errno == ERANGE)
329                 return -1;
330         return value;
331 }
332
333 /*
334  * Get sched_mc or sched_smt settings
335  * Pass "mc" or "smt" as argument
336  *
337  * Returns negative value on failure
338  */
339 int sysfs_set_sched(const char *smt_mc, int val)
340 {
341         char linebuf[MAX_LINE_LEN];
342         char path[SYSFS_PATH_MAX];
343         struct stat statbuf;
344
345         if (strcmp("mc", smt_mc) && strcmp("smt", smt_mc))
346                 return -EINVAL;
347
348         snprintf(path, sizeof(path),
349                 PATH_TO_CPU "sched_%s_power_savings", smt_mc);
350         sprintf(linebuf, "%d", val);
351
352         if (stat(path, &statbuf) != 0)
353                 return -ENODEV;
354
355         if (sysfs_write_file(path, linebuf, MAX_LINE_LEN) == 0)
356                 return -1;
357         return 0;
358 }