Merge tag 'pm+acpi-3.11-rc1' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael...
[linux-2.6-block.git] / tools / power / cpupower / utils / helpers / sysfs.c
CommitLineData
7fe2f639
DB
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
19unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
20{
21 int fd;
2cd005ca 22 ssize_t numread;
7fe2f639 23
2cd005ca
DB
24 fd = open(path, O_RDONLY);
25 if (fd == -1)
7fe2f639
DB
26 return 0;
27
28 numread = read(fd, buf, buflen - 1);
2cd005ca 29 if (numread < 1) {
7fe2f639
DB
30 close(fd);
31 return 0;
32 }
33
34 buf[numread] = '\0';
35 close(fd);
36
2cd005ca 37 return (unsigned int) numread;
7fe2f639
DB
38}
39
7c74d2bc
TR
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 */
48int 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
7fe2f639
DB
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 */
98unsigned 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;
2cd005ca 103 ssize_t numread;
7fe2f639
DB
104
105 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
106 cpu, idlestate, fname);
107
2cd005ca
DB
108 fd = open(path, O_RDONLY);
109 if (fd == -1)
7fe2f639
DB
110 return 0;
111
112 numread = read(fd, buf, buflen - 1);
2cd005ca 113 if (numread < 1) {
7fe2f639
DB
114 close(fd);
115 return 0;
116 }
117
118 buf[numread] = '\0';
119 close(fd);
120
2cd005ca 121 return (unsigned int) numread;
7fe2f639
DB
122}
123
124/* read access to files which contain one numeric value */
125
126enum idlestate_value {
127 IDLESTATE_USAGE,
128 IDLESTATE_POWER,
129 IDLESTATE_LATENCY,
130 IDLESTATE_TIME,
131 MAX_IDLESTATE_VALUE_FILES
132};
133
134static 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
141static 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
2cd005ca 150 if (which >= MAX_IDLESTATE_VALUE_FILES)
7fe2f639
DB
151 return 0;
152
2cd005ca
DB
153 len = sysfs_idlestate_read_file(cpu, idlestate,
154 idlestate_value_files[which],
155 linebuf, sizeof(linebuf));
156 if (len == 0)
7fe2f639 157 return 0;
7fe2f639
DB
158
159 value = strtoull(linebuf, &endp, 0);
160
2cd005ca 161 if (endp == linebuf || errno == ERANGE)
7fe2f639
DB
162 return 0;
163
164 return value;
165}
166
167/* read access to files which contain one string */
168
169enum idlestate_string {
170 IDLESTATE_DESC,
171 IDLESTATE_NAME,
172 MAX_IDLESTATE_STRING_FILES
173};
174
175static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
176 [IDLESTATE_DESC] = "desc",
177 [IDLESTATE_NAME] = "name",
178};
179
180
2cd005ca
DB
181static char *sysfs_idlestate_get_one_string(unsigned int cpu,
182 unsigned int idlestate,
183 enum idlestate_string which)
7fe2f639
DB
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
2cd005ca
DB
192 len = sysfs_idlestate_read_file(cpu, idlestate,
193 idlestate_string_files[which],
194 linebuf, sizeof(linebuf));
195 if (len == 0)
7fe2f639
DB
196 return NULL;
197
2cd005ca
DB
198 result = strdup(linebuf);
199 if (result == NULL)
7fe2f639
DB
200 return NULL;
201
202 if (result[strlen(result) - 1] == '\n')
203 result[strlen(result) - 1] = '\0';
204
205 return result;
206}
207
2cd005ca
DB
208unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
209 unsigned int idlestate)
7fe2f639
DB
210{
211 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
212}
213
2cd005ca
DB
214unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
215 unsigned int idlestate)
7fe2f639
DB
216{
217 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
218}
219
2cd005ca
DB
220unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
221 unsigned int idlestate)
7fe2f639
DB
222{
223 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
224}
225
2cd005ca 226char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
7fe2f639
DB
227{
228 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
229}
230
2cd005ca 231char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
7fe2f639
DB
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 */
241int 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");
2cd005ca 249 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
7fe2f639
DB
250 return -ENODEV;
251
252 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
2cd005ca 253 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
7fe2f639
DB
254 return 0;
255
2cd005ca 256 while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
7fe2f639
DB
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 */
271static 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
285enum cpuidle_string {
286 CPUIDLE_GOVERNOR,
287 CPUIDLE_GOVERNOR_RO,
288 CPUIDLE_DRIVER,
289 MAX_CPUIDLE_STRING_FILES
290};
291
292static 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
2cd005ca 299static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
7fe2f639
DB
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
2cd005ca
DB
308 len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
309 linebuf, sizeof(linebuf));
310 if (len == 0)
7fe2f639
DB
311 return NULL;
312
2cd005ca
DB
313 result = strdup(linebuf);
314 if (result == NULL)
7fe2f639
DB
315 return NULL;
316
317 if (result[strlen(result) - 1] == '\n')
318 result[strlen(result) - 1] = '\0';
319
320 return result;
321}
322
2cd005ca 323char *sysfs_get_cpuidle_governor(void)
7fe2f639
DB
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
2cd005ca 332char *sysfs_get_cpuidle_driver(void)
7fe2f639
DB
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 */
2cd005ca 344int sysfs_get_sched(const char *smt_mc)
7fe2f639 345{
8e7fbcbc 346 return -ENODEV;
7fe2f639
DB
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 */
2cd005ca 355int sysfs_set_sched(const char *smt_mc, int val)
7fe2f639 356{
8e7fbcbc 357 return -ENODEV;
7fe2f639 358}