Merge remote-tracking branch 'asoc/topic/compress' into asoc-next
[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
0924c369
TR
90/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
91
92
7fe2f639
DB
93/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
94
0924c369
TR
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 */
104unsigned 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
7fe2f639
DB
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 */
125unsigned 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;
2cd005ca 130 ssize_t numread;
7fe2f639
DB
131
132 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
133 cpu, idlestate, fname);
134
2cd005ca
DB
135 fd = open(path, O_RDONLY);
136 if (fd == -1)
7fe2f639
DB
137 return 0;
138
139 numread = read(fd, buf, buflen - 1);
2cd005ca 140 if (numread < 1) {
7fe2f639
DB
141 close(fd);
142 return 0;
143 }
144
145 buf[numread] = '\0';
146 close(fd);
147
2cd005ca 148 return (unsigned int) numread;
7fe2f639
DB
149}
150
0924c369
TR
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 */
157static
158unsigned 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
7fe2f639
DB
185/* read access to files which contain one numeric value */
186
187enum idlestate_value {
188 IDLESTATE_USAGE,
189 IDLESTATE_POWER,
190 IDLESTATE_LATENCY,
191 IDLESTATE_TIME,
0924c369 192 IDLESTATE_DISABLE,
7fe2f639
DB
193 MAX_IDLESTATE_VALUE_FILES
194};
195
196static 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",
0924c369 201 [IDLESTATE_DISABLE] = "disable",
7fe2f639
DB
202};
203
204static 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
2cd005ca 213 if (which >= MAX_IDLESTATE_VALUE_FILES)
7fe2f639
DB
214 return 0;
215
2cd005ca
DB
216 len = sysfs_idlestate_read_file(cpu, idlestate,
217 idlestate_value_files[which],
218 linebuf, sizeof(linebuf));
219 if (len == 0)
7fe2f639 220 return 0;
7fe2f639
DB
221
222 value = strtoull(linebuf, &endp, 0);
223
2cd005ca 224 if (endp == linebuf || errno == ERANGE)
7fe2f639
DB
225 return 0;
226
227 return value;
228}
229
230/* read access to files which contain one string */
231
232enum idlestate_string {
233 IDLESTATE_DESC,
234 IDLESTATE_NAME,
235 MAX_IDLESTATE_STRING_FILES
236};
237
238static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
239 [IDLESTATE_DESC] = "desc",
240 [IDLESTATE_NAME] = "name",
241};
242
243
2cd005ca
DB
244static char *sysfs_idlestate_get_one_string(unsigned int cpu,
245 unsigned int idlestate,
246 enum idlestate_string which)
7fe2f639
DB
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
2cd005ca
DB
255 len = sysfs_idlestate_read_file(cpu, idlestate,
256 idlestate_string_files[which],
257 linebuf, sizeof(linebuf));
258 if (len == 0)
7fe2f639
DB
259 return NULL;
260
2cd005ca
DB
261 result = strdup(linebuf);
262 if (result == NULL)
7fe2f639
DB
263 return NULL;
264
265 if (result[strlen(result) - 1] == '\n')
266 result[strlen(result) - 1] = '\0';
267
268 return result;
269}
270
0924c369
TR
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 */
278int sysfs_is_idlestate_disabled(unsigned int cpu,
279 unsigned int idlestate)
280{
f4a5d17e 281 if (sysfs_get_idlestate_count(cpu) <= idlestate)
0924c369
TR
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 */
299int 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
f4a5d17e 306 if (sysfs_get_idlestate_count(cpu) <= idlestate)
0924c369
TR
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
2cd005ca 322unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
0924c369 323 unsigned int idlestate)
7fe2f639
DB
324{
325 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
326}
327
2cd005ca
DB
328unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
329 unsigned int idlestate)
7fe2f639
DB
330{
331 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
332}
333
2cd005ca
DB
334unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
335 unsigned int idlestate)
7fe2f639
DB
336{
337 return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
338}
339
2cd005ca 340char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
7fe2f639
DB
341{
342 return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
343}
344
2cd005ca 345char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
7fe2f639
DB
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 */
f605181a 355unsigned int sysfs_get_idlestate_count(unsigned int cpu)
7fe2f639
DB
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");
2cd005ca 363 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
7fe2f639
DB
364 return -ENODEV;
365
366 snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
2cd005ca 367 if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
7fe2f639
DB
368 return 0;
369
2cd005ca 370 while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
7fe2f639
DB
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 */
385static 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
399enum cpuidle_string {
400 CPUIDLE_GOVERNOR,
401 CPUIDLE_GOVERNOR_RO,
402 CPUIDLE_DRIVER,
403 MAX_CPUIDLE_STRING_FILES
404};
405
406static 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
2cd005ca 413static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
7fe2f639
DB
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
2cd005ca
DB
422 len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
423 linebuf, sizeof(linebuf));
424 if (len == 0)
7fe2f639
DB
425 return NULL;
426
2cd005ca
DB
427 result = strdup(linebuf);
428 if (result == NULL)
7fe2f639
DB
429 return NULL;
430
431 if (result[strlen(result) - 1] == '\n')
432 result[strlen(result) - 1] = '\0';
433
434 return result;
435}
436
2cd005ca 437char *sysfs_get_cpuidle_governor(void)
7fe2f639
DB
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
2cd005ca 446char *sysfs_get_cpuidle_driver(void)
7fe2f639
DB
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 */
2cd005ca 458int sysfs_get_sched(const char *smt_mc)
7fe2f639 459{
8e7fbcbc 460 return -ENODEV;
7fe2f639
DB
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 */
2cd005ca 469int sysfs_set_sched(const char *smt_mc, int val)
7fe2f639 470{
8e7fbcbc 471 return -ENODEV;
7fe2f639 472}