xref: /OK3568_Linux_fs/kernel/tools/power/cpupower/utils/helpers/sysfs.c (revision 4882a59341e53eb6f0b4789bf948001014eff981)
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