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