1*4882a593Smuzhiyun // SPDX-License-Identifier: GPL-2.0-only
2*4882a593Smuzhiyun /*
3*4882a593Smuzhiyun * (C) 2004-2009 Dominik Brodowski <linux@dominikbrodowski.de>
4*4882a593Smuzhiyun * (C) 2011 Thomas Renninger <trenn@novell.com> Novell Inc.
5*4882a593Smuzhiyun */
6*4882a593Smuzhiyun
7*4882a593Smuzhiyun #include <stdio.h>
8*4882a593Smuzhiyun #include <errno.h>
9*4882a593Smuzhiyun #include <stdlib.h>
10*4882a593Smuzhiyun #include <string.h>
11*4882a593Smuzhiyun #include <sys/types.h>
12*4882a593Smuzhiyun #include <sys/stat.h>
13*4882a593Smuzhiyun #include <fcntl.h>
14*4882a593Smuzhiyun #include <unistd.h>
15*4882a593Smuzhiyun
16*4882a593Smuzhiyun #include "helpers/sysfs.h"
17*4882a593Smuzhiyun
sysfs_read_file(const char * path,char * buf,size_t buflen)18*4882a593Smuzhiyun unsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
19*4882a593Smuzhiyun {
20*4882a593Smuzhiyun int fd;
21*4882a593Smuzhiyun ssize_t numread;
22*4882a593Smuzhiyun
23*4882a593Smuzhiyun fd = open(path, O_RDONLY);
24*4882a593Smuzhiyun if (fd == -1)
25*4882a593Smuzhiyun return 0;
26*4882a593Smuzhiyun
27*4882a593Smuzhiyun numread = read(fd, buf, buflen - 1);
28*4882a593Smuzhiyun if (numread < 1) {
29*4882a593Smuzhiyun close(fd);
30*4882a593Smuzhiyun return 0;
31*4882a593Smuzhiyun }
32*4882a593Smuzhiyun
33*4882a593Smuzhiyun buf[numread] = '\0';
34*4882a593Smuzhiyun close(fd);
35*4882a593Smuzhiyun
36*4882a593Smuzhiyun return (unsigned int) numread;
37*4882a593Smuzhiyun }
38*4882a593Smuzhiyun
39*4882a593Smuzhiyun /*
40*4882a593Smuzhiyun * Detect whether a CPU is online
41*4882a593Smuzhiyun *
42*4882a593Smuzhiyun * Returns:
43*4882a593Smuzhiyun * 1 -> if CPU is online
44*4882a593Smuzhiyun * 0 -> if CPU is offline
45*4882a593Smuzhiyun * negative errno values in error case
46*4882a593Smuzhiyun */
sysfs_is_cpu_online(unsigned int cpu)47*4882a593Smuzhiyun int sysfs_is_cpu_online(unsigned int cpu)
48*4882a593Smuzhiyun {
49*4882a593Smuzhiyun char path[SYSFS_PATH_MAX];
50*4882a593Smuzhiyun int fd;
51*4882a593Smuzhiyun ssize_t numread;
52*4882a593Smuzhiyun unsigned long long value;
53*4882a593Smuzhiyun char linebuf[MAX_LINE_LEN];
54*4882a593Smuzhiyun char *endp;
55*4882a593Smuzhiyun struct stat statbuf;
56*4882a593Smuzhiyun
57*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
58*4882a593Smuzhiyun
59*4882a593Smuzhiyun if (stat(path, &statbuf) != 0)
60*4882a593Smuzhiyun return 0;
61*4882a593Smuzhiyun
62*4882a593Smuzhiyun /*
63*4882a593Smuzhiyun * kernel without CONFIG_HOTPLUG_CPU
64*4882a593Smuzhiyun * -> cpuX directory exists, but not cpuX/online file
65*4882a593Smuzhiyun */
66*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
67*4882a593Smuzhiyun if (stat(path, &statbuf) != 0)
68*4882a593Smuzhiyun return 1;
69*4882a593Smuzhiyun
70*4882a593Smuzhiyun fd = open(path, O_RDONLY);
71*4882a593Smuzhiyun if (fd == -1)
72*4882a593Smuzhiyun return -errno;
73*4882a593Smuzhiyun
74*4882a593Smuzhiyun numread = read(fd, linebuf, MAX_LINE_LEN - 1);
75*4882a593Smuzhiyun if (numread < 1) {
76*4882a593Smuzhiyun close(fd);
77*4882a593Smuzhiyun return -EIO;
78*4882a593Smuzhiyun }
79*4882a593Smuzhiyun linebuf[numread] = '\0';
80*4882a593Smuzhiyun close(fd);
81*4882a593Smuzhiyun
82*4882a593Smuzhiyun value = strtoull(linebuf, &endp, 0);
83*4882a593Smuzhiyun if (value > 1)
84*4882a593Smuzhiyun return -EINVAL;
85*4882a593Smuzhiyun
86*4882a593Smuzhiyun return value;
87*4882a593Smuzhiyun }
88*4882a593Smuzhiyun
89*4882a593Smuzhiyun /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
90*4882a593Smuzhiyun
91*4882a593Smuzhiyun
92*4882a593Smuzhiyun /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
93*4882a593Smuzhiyun
94*4882a593Smuzhiyun /*
95*4882a593Smuzhiyun * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
96*4882a593Smuzhiyun * exists.
97*4882a593Smuzhiyun * For example the functionality to disable c-states was introduced in later
98*4882a593Smuzhiyun * kernel versions, this function can be used to explicitly check for this
99*4882a593Smuzhiyun * feature.
100*4882a593Smuzhiyun *
101*4882a593Smuzhiyun * returns 1 if the file exists, 0 otherwise.
102*4882a593Smuzhiyun */
sysfs_idlestate_file_exists(unsigned int cpu,unsigned int idlestate,const char * fname)103*4882a593Smuzhiyun unsigned int sysfs_idlestate_file_exists(unsigned int cpu,
104*4882a593Smuzhiyun unsigned int idlestate,
105*4882a593Smuzhiyun const char *fname)
106*4882a593Smuzhiyun {
107*4882a593Smuzhiyun char path[SYSFS_PATH_MAX];
108*4882a593Smuzhiyun struct stat statbuf;
109*4882a593Smuzhiyun
110*4882a593Smuzhiyun
111*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
112*4882a593Smuzhiyun cpu, idlestate, fname);
113*4882a593Smuzhiyun if (stat(path, &statbuf) != 0)
114*4882a593Smuzhiyun return 0;
115*4882a593Smuzhiyun return 1;
116*4882a593Smuzhiyun }
117*4882a593Smuzhiyun
118*4882a593Smuzhiyun /*
119*4882a593Smuzhiyun * helper function to read file from /sys into given buffer
120*4882a593Smuzhiyun * fname is a relative path under "cpuX/cpuidle/stateX/" dir
121*4882a593Smuzhiyun * cstates starting with 0, C0 is not counted as cstate.
122*4882a593Smuzhiyun * This means if you want C1 info, pass 0 as idlestate param
123*4882a593Smuzhiyun */
sysfs_idlestate_read_file(unsigned int cpu,unsigned int idlestate,const char * fname,char * buf,size_t buflen)124*4882a593Smuzhiyun unsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
125*4882a593Smuzhiyun const char *fname, char *buf, size_t buflen)
126*4882a593Smuzhiyun {
127*4882a593Smuzhiyun char path[SYSFS_PATH_MAX];
128*4882a593Smuzhiyun int fd;
129*4882a593Smuzhiyun ssize_t numread;
130*4882a593Smuzhiyun
131*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
132*4882a593Smuzhiyun cpu, idlestate, fname);
133*4882a593Smuzhiyun
134*4882a593Smuzhiyun fd = open(path, O_RDONLY);
135*4882a593Smuzhiyun if (fd == -1)
136*4882a593Smuzhiyun return 0;
137*4882a593Smuzhiyun
138*4882a593Smuzhiyun numread = read(fd, buf, buflen - 1);
139*4882a593Smuzhiyun if (numread < 1) {
140*4882a593Smuzhiyun close(fd);
141*4882a593Smuzhiyun return 0;
142*4882a593Smuzhiyun }
143*4882a593Smuzhiyun
144*4882a593Smuzhiyun buf[numread] = '\0';
145*4882a593Smuzhiyun close(fd);
146*4882a593Smuzhiyun
147*4882a593Smuzhiyun return (unsigned int) numread;
148*4882a593Smuzhiyun }
149*4882a593Smuzhiyun
150*4882a593Smuzhiyun /*
151*4882a593Smuzhiyun * helper function to write a new value to a /sys file
152*4882a593Smuzhiyun * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
153*4882a593Smuzhiyun *
154*4882a593Smuzhiyun * Returns the number of bytes written or 0 on error
155*4882a593Smuzhiyun */
156*4882a593Smuzhiyun static
sysfs_idlestate_write_file(unsigned int cpu,unsigned int idlestate,const char * fname,const char * value,size_t len)157*4882a593Smuzhiyun unsigned int sysfs_idlestate_write_file(unsigned int cpu,
158*4882a593Smuzhiyun unsigned int idlestate,
159*4882a593Smuzhiyun const char *fname,
160*4882a593Smuzhiyun const char *value, size_t len)
161*4882a593Smuzhiyun {
162*4882a593Smuzhiyun char path[SYSFS_PATH_MAX];
163*4882a593Smuzhiyun int fd;
164*4882a593Smuzhiyun ssize_t numwrite;
165*4882a593Smuzhiyun
166*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
167*4882a593Smuzhiyun cpu, idlestate, fname);
168*4882a593Smuzhiyun
169*4882a593Smuzhiyun fd = open(path, O_WRONLY);
170*4882a593Smuzhiyun if (fd == -1)
171*4882a593Smuzhiyun return 0;
172*4882a593Smuzhiyun
173*4882a593Smuzhiyun numwrite = write(fd, value, len);
174*4882a593Smuzhiyun if (numwrite < 1) {
175*4882a593Smuzhiyun close(fd);
176*4882a593Smuzhiyun return 0;
177*4882a593Smuzhiyun }
178*4882a593Smuzhiyun
179*4882a593Smuzhiyun close(fd);
180*4882a593Smuzhiyun
181*4882a593Smuzhiyun return (unsigned int) numwrite;
182*4882a593Smuzhiyun }
183*4882a593Smuzhiyun
184*4882a593Smuzhiyun /* read access to files which contain one numeric value */
185*4882a593Smuzhiyun
186*4882a593Smuzhiyun enum idlestate_value {
187*4882a593Smuzhiyun IDLESTATE_USAGE,
188*4882a593Smuzhiyun IDLESTATE_POWER,
189*4882a593Smuzhiyun IDLESTATE_LATENCY,
190*4882a593Smuzhiyun IDLESTATE_TIME,
191*4882a593Smuzhiyun IDLESTATE_DISABLE,
192*4882a593Smuzhiyun MAX_IDLESTATE_VALUE_FILES
193*4882a593Smuzhiyun };
194*4882a593Smuzhiyun
195*4882a593Smuzhiyun static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
196*4882a593Smuzhiyun [IDLESTATE_USAGE] = "usage",
197*4882a593Smuzhiyun [IDLESTATE_POWER] = "power",
198*4882a593Smuzhiyun [IDLESTATE_LATENCY] = "latency",
199*4882a593Smuzhiyun [IDLESTATE_TIME] = "time",
200*4882a593Smuzhiyun [IDLESTATE_DISABLE] = "disable",
201*4882a593Smuzhiyun };
202*4882a593Smuzhiyun
sysfs_idlestate_get_one_value(unsigned int cpu,unsigned int idlestate,enum idlestate_value which)203*4882a593Smuzhiyun static unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
204*4882a593Smuzhiyun unsigned int idlestate,
205*4882a593Smuzhiyun enum idlestate_value which)
206*4882a593Smuzhiyun {
207*4882a593Smuzhiyun unsigned long long value;
208*4882a593Smuzhiyun unsigned int len;
209*4882a593Smuzhiyun char linebuf[MAX_LINE_LEN];
210*4882a593Smuzhiyun char *endp;
211*4882a593Smuzhiyun
212*4882a593Smuzhiyun if (which >= MAX_IDLESTATE_VALUE_FILES)
213*4882a593Smuzhiyun return 0;
214*4882a593Smuzhiyun
215*4882a593Smuzhiyun len = sysfs_idlestate_read_file(cpu, idlestate,
216*4882a593Smuzhiyun idlestate_value_files[which],
217*4882a593Smuzhiyun linebuf, sizeof(linebuf));
218*4882a593Smuzhiyun if (len == 0)
219*4882a593Smuzhiyun return 0;
220*4882a593Smuzhiyun
221*4882a593Smuzhiyun value = strtoull(linebuf, &endp, 0);
222*4882a593Smuzhiyun
223*4882a593Smuzhiyun if (endp == linebuf || errno == ERANGE)
224*4882a593Smuzhiyun return 0;
225*4882a593Smuzhiyun
226*4882a593Smuzhiyun return value;
227*4882a593Smuzhiyun }
228*4882a593Smuzhiyun
229*4882a593Smuzhiyun /* read access to files which contain one string */
230*4882a593Smuzhiyun
231*4882a593Smuzhiyun enum idlestate_string {
232*4882a593Smuzhiyun IDLESTATE_DESC,
233*4882a593Smuzhiyun IDLESTATE_NAME,
234*4882a593Smuzhiyun MAX_IDLESTATE_STRING_FILES
235*4882a593Smuzhiyun };
236*4882a593Smuzhiyun
237*4882a593Smuzhiyun static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
238*4882a593Smuzhiyun [IDLESTATE_DESC] = "desc",
239*4882a593Smuzhiyun [IDLESTATE_NAME] = "name",
240*4882a593Smuzhiyun };
241*4882a593Smuzhiyun
242*4882a593Smuzhiyun
sysfs_idlestate_get_one_string(unsigned int cpu,unsigned int idlestate,enum idlestate_string which)243*4882a593Smuzhiyun static char *sysfs_idlestate_get_one_string(unsigned int cpu,
244*4882a593Smuzhiyun unsigned int idlestate,
245*4882a593Smuzhiyun enum idlestate_string which)
246*4882a593Smuzhiyun {
247*4882a593Smuzhiyun char linebuf[MAX_LINE_LEN];
248*4882a593Smuzhiyun char *result;
249*4882a593Smuzhiyun unsigned int len;
250*4882a593Smuzhiyun
251*4882a593Smuzhiyun if (which >= MAX_IDLESTATE_STRING_FILES)
252*4882a593Smuzhiyun return NULL;
253*4882a593Smuzhiyun
254*4882a593Smuzhiyun len = sysfs_idlestate_read_file(cpu, idlestate,
255*4882a593Smuzhiyun idlestate_string_files[which],
256*4882a593Smuzhiyun linebuf, sizeof(linebuf));
257*4882a593Smuzhiyun if (len == 0)
258*4882a593Smuzhiyun return NULL;
259*4882a593Smuzhiyun
260*4882a593Smuzhiyun result = strdup(linebuf);
261*4882a593Smuzhiyun if (result == NULL)
262*4882a593Smuzhiyun return NULL;
263*4882a593Smuzhiyun
264*4882a593Smuzhiyun if (result[strlen(result) - 1] == '\n')
265*4882a593Smuzhiyun result[strlen(result) - 1] = '\0';
266*4882a593Smuzhiyun
267*4882a593Smuzhiyun return result;
268*4882a593Smuzhiyun }
269*4882a593Smuzhiyun
270*4882a593Smuzhiyun /*
271*4882a593Smuzhiyun * Returns:
272*4882a593Smuzhiyun * 1 if disabled
273*4882a593Smuzhiyun * 0 if enabled
274*4882a593Smuzhiyun * -1 if idlestate is not available
275*4882a593Smuzhiyun * -2 if disabling is not supported by the kernel
276*4882a593Smuzhiyun */
sysfs_is_idlestate_disabled(unsigned int cpu,unsigned int idlestate)277*4882a593Smuzhiyun int sysfs_is_idlestate_disabled(unsigned int cpu,
278*4882a593Smuzhiyun unsigned int idlestate)
279*4882a593Smuzhiyun {
280*4882a593Smuzhiyun if (sysfs_get_idlestate_count(cpu) <= idlestate)
281*4882a593Smuzhiyun return -1;
282*4882a593Smuzhiyun
283*4882a593Smuzhiyun if (!sysfs_idlestate_file_exists(cpu, idlestate,
284*4882a593Smuzhiyun idlestate_value_files[IDLESTATE_DISABLE]))
285*4882a593Smuzhiyun return -2;
286*4882a593Smuzhiyun return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
287*4882a593Smuzhiyun }
288*4882a593Smuzhiyun
289*4882a593Smuzhiyun /*
290*4882a593Smuzhiyun * Pass 1 as last argument to disable or 0 to enable the state
291*4882a593Smuzhiyun * Returns:
292*4882a593Smuzhiyun * 0 on success
293*4882a593Smuzhiyun * negative values on error, for example:
294*4882a593Smuzhiyun * -1 if idlestate is not available
295*4882a593Smuzhiyun * -2 if disabling is not supported by the kernel
296*4882a593Smuzhiyun * -3 No write access to disable/enable C-states
297*4882a593Smuzhiyun */
sysfs_idlestate_disable(unsigned int cpu,unsigned int idlestate,unsigned int disable)298*4882a593Smuzhiyun int sysfs_idlestate_disable(unsigned int cpu,
299*4882a593Smuzhiyun unsigned int idlestate,
300*4882a593Smuzhiyun unsigned int disable)
301*4882a593Smuzhiyun {
302*4882a593Smuzhiyun char value[SYSFS_PATH_MAX];
303*4882a593Smuzhiyun int bytes_written;
304*4882a593Smuzhiyun
305*4882a593Smuzhiyun if (sysfs_get_idlestate_count(cpu) <= idlestate)
306*4882a593Smuzhiyun return -1;
307*4882a593Smuzhiyun
308*4882a593Smuzhiyun if (!sysfs_idlestate_file_exists(cpu, idlestate,
309*4882a593Smuzhiyun idlestate_value_files[IDLESTATE_DISABLE]))
310*4882a593Smuzhiyun return -2;
311*4882a593Smuzhiyun
312*4882a593Smuzhiyun snprintf(value, SYSFS_PATH_MAX, "%u", disable);
313*4882a593Smuzhiyun
314*4882a593Smuzhiyun bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
315*4882a593Smuzhiyun value, sizeof(disable));
316*4882a593Smuzhiyun if (bytes_written)
317*4882a593Smuzhiyun return 0;
318*4882a593Smuzhiyun return -3;
319*4882a593Smuzhiyun }
320*4882a593Smuzhiyun
sysfs_get_idlestate_latency(unsigned int cpu,unsigned int idlestate)321*4882a593Smuzhiyun unsigned long sysfs_get_idlestate_latency(unsigned int cpu,
322*4882a593Smuzhiyun unsigned int idlestate)
323*4882a593Smuzhiyun {
324*4882a593Smuzhiyun return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
325*4882a593Smuzhiyun }
326*4882a593Smuzhiyun
sysfs_get_idlestate_usage(unsigned int cpu,unsigned int idlestate)327*4882a593Smuzhiyun unsigned long sysfs_get_idlestate_usage(unsigned int cpu,
328*4882a593Smuzhiyun unsigned int idlestate)
329*4882a593Smuzhiyun {
330*4882a593Smuzhiyun return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
331*4882a593Smuzhiyun }
332*4882a593Smuzhiyun
sysfs_get_idlestate_time(unsigned int cpu,unsigned int idlestate)333*4882a593Smuzhiyun unsigned long long sysfs_get_idlestate_time(unsigned int cpu,
334*4882a593Smuzhiyun unsigned int idlestate)
335*4882a593Smuzhiyun {
336*4882a593Smuzhiyun return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
337*4882a593Smuzhiyun }
338*4882a593Smuzhiyun
sysfs_get_idlestate_name(unsigned int cpu,unsigned int idlestate)339*4882a593Smuzhiyun char *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
340*4882a593Smuzhiyun {
341*4882a593Smuzhiyun return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
342*4882a593Smuzhiyun }
343*4882a593Smuzhiyun
sysfs_get_idlestate_desc(unsigned int cpu,unsigned int idlestate)344*4882a593Smuzhiyun char *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
345*4882a593Smuzhiyun {
346*4882a593Smuzhiyun return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
347*4882a593Smuzhiyun }
348*4882a593Smuzhiyun
349*4882a593Smuzhiyun /*
350*4882a593Smuzhiyun * Returns number of supported C-states of CPU core cpu
351*4882a593Smuzhiyun * Negativ in error case
352*4882a593Smuzhiyun * Zero if cpuidle does not export any C-states
353*4882a593Smuzhiyun */
sysfs_get_idlestate_count(unsigned int cpu)354*4882a593Smuzhiyun unsigned int sysfs_get_idlestate_count(unsigned int cpu)
355*4882a593Smuzhiyun {
356*4882a593Smuzhiyun char file[SYSFS_PATH_MAX];
357*4882a593Smuzhiyun struct stat statbuf;
358*4882a593Smuzhiyun int idlestates = 1;
359*4882a593Smuzhiyun
360*4882a593Smuzhiyun
361*4882a593Smuzhiyun snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
362*4882a593Smuzhiyun if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
363*4882a593Smuzhiyun return 0;
364*4882a593Smuzhiyun
365*4882a593Smuzhiyun snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
366*4882a593Smuzhiyun if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
367*4882a593Smuzhiyun return 0;
368*4882a593Smuzhiyun
369*4882a593Smuzhiyun while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
370*4882a593Smuzhiyun snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
371*4882a593Smuzhiyun "cpu%u/cpuidle/state%d", cpu, idlestates);
372*4882a593Smuzhiyun idlestates++;
373*4882a593Smuzhiyun }
374*4882a593Smuzhiyun idlestates--;
375*4882a593Smuzhiyun return idlestates;
376*4882a593Smuzhiyun }
377*4882a593Smuzhiyun
378*4882a593Smuzhiyun /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
379*4882a593Smuzhiyun
380*4882a593Smuzhiyun /*
381*4882a593Smuzhiyun * helper function to read file from /sys into given buffer
382*4882a593Smuzhiyun * fname is a relative path under "cpu/cpuidle/" dir
383*4882a593Smuzhiyun */
sysfs_cpuidle_read_file(const char * fname,char * buf,size_t buflen)384*4882a593Smuzhiyun static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
385*4882a593Smuzhiyun size_t buflen)
386*4882a593Smuzhiyun {
387*4882a593Smuzhiyun char path[SYSFS_PATH_MAX];
388*4882a593Smuzhiyun
389*4882a593Smuzhiyun snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
390*4882a593Smuzhiyun
391*4882a593Smuzhiyun return sysfs_read_file(path, buf, buflen);
392*4882a593Smuzhiyun }
393*4882a593Smuzhiyun
394*4882a593Smuzhiyun
395*4882a593Smuzhiyun
396*4882a593Smuzhiyun /* read access to files which contain one string */
397*4882a593Smuzhiyun
398*4882a593Smuzhiyun enum cpuidle_string {
399*4882a593Smuzhiyun CPUIDLE_GOVERNOR,
400*4882a593Smuzhiyun CPUIDLE_GOVERNOR_RO,
401*4882a593Smuzhiyun CPUIDLE_DRIVER,
402*4882a593Smuzhiyun MAX_CPUIDLE_STRING_FILES
403*4882a593Smuzhiyun };
404*4882a593Smuzhiyun
405*4882a593Smuzhiyun static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
406*4882a593Smuzhiyun [CPUIDLE_GOVERNOR] = "current_governor",
407*4882a593Smuzhiyun [CPUIDLE_GOVERNOR_RO] = "current_governor_ro",
408*4882a593Smuzhiyun [CPUIDLE_DRIVER] = "current_driver",
409*4882a593Smuzhiyun };
410*4882a593Smuzhiyun
411*4882a593Smuzhiyun
sysfs_cpuidle_get_one_string(enum cpuidle_string which)412*4882a593Smuzhiyun static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
413*4882a593Smuzhiyun {
414*4882a593Smuzhiyun char linebuf[MAX_LINE_LEN];
415*4882a593Smuzhiyun char *result;
416*4882a593Smuzhiyun unsigned int len;
417*4882a593Smuzhiyun
418*4882a593Smuzhiyun if (which >= MAX_CPUIDLE_STRING_FILES)
419*4882a593Smuzhiyun return NULL;
420*4882a593Smuzhiyun
421*4882a593Smuzhiyun len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
422*4882a593Smuzhiyun linebuf, sizeof(linebuf));
423*4882a593Smuzhiyun if (len == 0)
424*4882a593Smuzhiyun return NULL;
425*4882a593Smuzhiyun
426*4882a593Smuzhiyun result = strdup(linebuf);
427*4882a593Smuzhiyun if (result == NULL)
428*4882a593Smuzhiyun return NULL;
429*4882a593Smuzhiyun
430*4882a593Smuzhiyun if (result[strlen(result) - 1] == '\n')
431*4882a593Smuzhiyun result[strlen(result) - 1] = '\0';
432*4882a593Smuzhiyun
433*4882a593Smuzhiyun return result;
434*4882a593Smuzhiyun }
435*4882a593Smuzhiyun
sysfs_get_cpuidle_governor(void)436*4882a593Smuzhiyun char *sysfs_get_cpuidle_governor(void)
437*4882a593Smuzhiyun {
438*4882a593Smuzhiyun char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
439*4882a593Smuzhiyun if (!tmp)
440*4882a593Smuzhiyun return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
441*4882a593Smuzhiyun else
442*4882a593Smuzhiyun return tmp;
443*4882a593Smuzhiyun }
444*4882a593Smuzhiyun
sysfs_get_cpuidle_driver(void)445*4882a593Smuzhiyun char *sysfs_get_cpuidle_driver(void)
446*4882a593Smuzhiyun {
447*4882a593Smuzhiyun return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
448*4882a593Smuzhiyun }
449*4882a593Smuzhiyun /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
450*4882a593Smuzhiyun
451*4882a593Smuzhiyun /*
452*4882a593Smuzhiyun * Get sched_mc or sched_smt settings
453*4882a593Smuzhiyun * Pass "mc" or "smt" as argument
454*4882a593Smuzhiyun *
455*4882a593Smuzhiyun * Returns negative value on failure
456*4882a593Smuzhiyun */
sysfs_get_sched(const char * smt_mc)457*4882a593Smuzhiyun int sysfs_get_sched(const char *smt_mc)
458*4882a593Smuzhiyun {
459*4882a593Smuzhiyun return -ENODEV;
460*4882a593Smuzhiyun }
461*4882a593Smuzhiyun
462*4882a593Smuzhiyun /*
463*4882a593Smuzhiyun * Get sched_mc or sched_smt settings
464*4882a593Smuzhiyun * Pass "mc" or "smt" as argument
465*4882a593Smuzhiyun *
466*4882a593Smuzhiyun * Returns negative value on failure
467*4882a593Smuzhiyun */
sysfs_set_sched(const char * smt_mc,int val)468*4882a593Smuzhiyun int sysfs_set_sched(const char *smt_mc, int val)
469*4882a593Smuzhiyun {
470*4882a593Smuzhiyun return -ENODEV;
471*4882a593Smuzhiyun }
472