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