162306a36Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
462306a36Sopenharmony_ci *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci
762306a36Sopenharmony_ci#include <stdio.h>
862306a36Sopenharmony_ci#include <errno.h>
962306a36Sopenharmony_ci#include <stdlib.h>
1062306a36Sopenharmony_ci#include <string.h>
1162306a36Sopenharmony_ci#include <sys/types.h>
1262306a36Sopenharmony_ci#include <sys/stat.h>
1362306a36Sopenharmony_ci#include <fcntl.h>
1462306a36Sopenharmony_ci#include <unistd.h>
1562306a36Sopenharmony_ci
1662306a36Sopenharmony_ci#include "helpers/sysfs.h"
1762306a36Sopenharmony_ci
1862306a36Sopenharmony_ciunsigned int sysfs_read_file(const char *path, char *buf, size_t buflen)
1962306a36Sopenharmony_ci{
2062306a36Sopenharmony_ci	int fd;
2162306a36Sopenharmony_ci	ssize_t numread;
2262306a36Sopenharmony_ci
2362306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
2462306a36Sopenharmony_ci	if (fd == -1)
2562306a36Sopenharmony_ci		return 0;
2662306a36Sopenharmony_ci
2762306a36Sopenharmony_ci	numread = read(fd, buf, buflen - 1);
2862306a36Sopenharmony_ci	if (numread < 1) {
2962306a36Sopenharmony_ci		close(fd);
3062306a36Sopenharmony_ci		return 0;
3162306a36Sopenharmony_ci	}
3262306a36Sopenharmony_ci
3362306a36Sopenharmony_ci	buf[numread] = '\0';
3462306a36Sopenharmony_ci	close(fd);
3562306a36Sopenharmony_ci
3662306a36Sopenharmony_ci	return (unsigned int) numread;
3762306a36Sopenharmony_ci}
3862306a36Sopenharmony_ci
3962306a36Sopenharmony_ci/*
4062306a36Sopenharmony_ci * Detect whether a CPU is online
4162306a36Sopenharmony_ci *
4262306a36Sopenharmony_ci * Returns:
4362306a36Sopenharmony_ci *     1 -> if CPU is online
4462306a36Sopenharmony_ci *     0 -> if CPU is offline
4562306a36Sopenharmony_ci *     negative errno values in error case
4662306a36Sopenharmony_ci */
4762306a36Sopenharmony_ciint sysfs_is_cpu_online(unsigned int cpu)
4862306a36Sopenharmony_ci{
4962306a36Sopenharmony_ci	char path[SYSFS_PATH_MAX];
5062306a36Sopenharmony_ci	int fd;
5162306a36Sopenharmony_ci	ssize_t numread;
5262306a36Sopenharmony_ci	unsigned long long value;
5362306a36Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
5462306a36Sopenharmony_ci	char *endp;
5562306a36Sopenharmony_ci	struct stat statbuf;
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u", cpu);
5862306a36Sopenharmony_ci
5962306a36Sopenharmony_ci	if (stat(path, &statbuf) != 0)
6062306a36Sopenharmony_ci		return 0;
6162306a36Sopenharmony_ci
6262306a36Sopenharmony_ci	/*
6362306a36Sopenharmony_ci	 * kernel without CONFIG_HOTPLUG_CPU
6462306a36Sopenharmony_ci	 * -> cpuX directory exists, but not cpuX/online file
6562306a36Sopenharmony_ci	 */
6662306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/online", cpu);
6762306a36Sopenharmony_ci	if (stat(path, &statbuf) != 0)
6862306a36Sopenharmony_ci		return 1;
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
7162306a36Sopenharmony_ci	if (fd == -1)
7262306a36Sopenharmony_ci		return -errno;
7362306a36Sopenharmony_ci
7462306a36Sopenharmony_ci	numread = read(fd, linebuf, MAX_LINE_LEN - 1);
7562306a36Sopenharmony_ci	if (numread < 1) {
7662306a36Sopenharmony_ci		close(fd);
7762306a36Sopenharmony_ci		return -EIO;
7862306a36Sopenharmony_ci	}
7962306a36Sopenharmony_ci	linebuf[numread] = '\0';
8062306a36Sopenharmony_ci	close(fd);
8162306a36Sopenharmony_ci
8262306a36Sopenharmony_ci	value = strtoull(linebuf, &endp, 0);
8362306a36Sopenharmony_ci	if (value > 1)
8462306a36Sopenharmony_ci		return -EINVAL;
8562306a36Sopenharmony_ci
8662306a36Sopenharmony_ci	return value;
8762306a36Sopenharmony_ci}
8862306a36Sopenharmony_ci
8962306a36Sopenharmony_ci/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
9062306a36Sopenharmony_ci
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_ci/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
9362306a36Sopenharmony_ci
9462306a36Sopenharmony_ci/*
9562306a36Sopenharmony_ci * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
9662306a36Sopenharmony_ci * exists.
9762306a36Sopenharmony_ci * For example the functionality to disable c-states was introduced in later
9862306a36Sopenharmony_ci * kernel versions, this function can be used to explicitly check for this
9962306a36Sopenharmony_ci * feature.
10062306a36Sopenharmony_ci *
10162306a36Sopenharmony_ci * returns 1 if the file exists, 0 otherwise.
10262306a36Sopenharmony_ci */
10362306a36Sopenharmony_ciunsigned int sysfs_idlestate_file_exists(unsigned int cpu,
10462306a36Sopenharmony_ci					 unsigned int idlestate,
10562306a36Sopenharmony_ci					 const char *fname)
10662306a36Sopenharmony_ci{
10762306a36Sopenharmony_ci	char path[SYSFS_PATH_MAX];
10862306a36Sopenharmony_ci	struct stat statbuf;
10962306a36Sopenharmony_ci
11062306a36Sopenharmony_ci
11162306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
11262306a36Sopenharmony_ci		 cpu, idlestate, fname);
11362306a36Sopenharmony_ci	if (stat(path, &statbuf) != 0)
11462306a36Sopenharmony_ci		return 0;
11562306a36Sopenharmony_ci	return 1;
11662306a36Sopenharmony_ci}
11762306a36Sopenharmony_ci
11862306a36Sopenharmony_ci/*
11962306a36Sopenharmony_ci * helper function to read file from /sys into given buffer
12062306a36Sopenharmony_ci * fname is a relative path under "cpuX/cpuidle/stateX/" dir
12162306a36Sopenharmony_ci * cstates starting with 0, C0 is not counted as cstate.
12262306a36Sopenharmony_ci * This means if you want C1 info, pass 0 as idlestate param
12362306a36Sopenharmony_ci */
12462306a36Sopenharmony_ciunsigned int sysfs_idlestate_read_file(unsigned int cpu, unsigned int idlestate,
12562306a36Sopenharmony_ci			     const char *fname, char *buf, size_t buflen)
12662306a36Sopenharmony_ci{
12762306a36Sopenharmony_ci	char path[SYSFS_PATH_MAX];
12862306a36Sopenharmony_ci	int fd;
12962306a36Sopenharmony_ci	ssize_t numread;
13062306a36Sopenharmony_ci
13162306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
13262306a36Sopenharmony_ci		 cpu, idlestate, fname);
13362306a36Sopenharmony_ci
13462306a36Sopenharmony_ci	fd = open(path, O_RDONLY);
13562306a36Sopenharmony_ci	if (fd == -1)
13662306a36Sopenharmony_ci		return 0;
13762306a36Sopenharmony_ci
13862306a36Sopenharmony_ci	numread = read(fd, buf, buflen - 1);
13962306a36Sopenharmony_ci	if (numread < 1) {
14062306a36Sopenharmony_ci		close(fd);
14162306a36Sopenharmony_ci		return 0;
14262306a36Sopenharmony_ci	}
14362306a36Sopenharmony_ci
14462306a36Sopenharmony_ci	buf[numread] = '\0';
14562306a36Sopenharmony_ci	close(fd);
14662306a36Sopenharmony_ci
14762306a36Sopenharmony_ci	return (unsigned int) numread;
14862306a36Sopenharmony_ci}
14962306a36Sopenharmony_ci
15062306a36Sopenharmony_ci/*
15162306a36Sopenharmony_ci * helper function to write a new value to a /sys file
15262306a36Sopenharmony_ci * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
15362306a36Sopenharmony_ci *
15462306a36Sopenharmony_ci * Returns the number of bytes written or 0 on error
15562306a36Sopenharmony_ci */
15662306a36Sopenharmony_cistatic
15762306a36Sopenharmony_ciunsigned int sysfs_idlestate_write_file(unsigned int cpu,
15862306a36Sopenharmony_ci					unsigned int idlestate,
15962306a36Sopenharmony_ci					const char *fname,
16062306a36Sopenharmony_ci					const char *value, size_t len)
16162306a36Sopenharmony_ci{
16262306a36Sopenharmony_ci	char path[SYSFS_PATH_MAX];
16362306a36Sopenharmony_ci	int fd;
16462306a36Sopenharmony_ci	ssize_t numwrite;
16562306a36Sopenharmony_ci
16662306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
16762306a36Sopenharmony_ci		 cpu, idlestate, fname);
16862306a36Sopenharmony_ci
16962306a36Sopenharmony_ci	fd = open(path, O_WRONLY);
17062306a36Sopenharmony_ci	if (fd == -1)
17162306a36Sopenharmony_ci		return 0;
17262306a36Sopenharmony_ci
17362306a36Sopenharmony_ci	numwrite = write(fd, value, len);
17462306a36Sopenharmony_ci	if (numwrite < 1) {
17562306a36Sopenharmony_ci		close(fd);
17662306a36Sopenharmony_ci		return 0;
17762306a36Sopenharmony_ci	}
17862306a36Sopenharmony_ci
17962306a36Sopenharmony_ci	close(fd);
18062306a36Sopenharmony_ci
18162306a36Sopenharmony_ci	return (unsigned int) numwrite;
18262306a36Sopenharmony_ci}
18362306a36Sopenharmony_ci
18462306a36Sopenharmony_ci/* read access to files which contain one numeric value */
18562306a36Sopenharmony_ci
18662306a36Sopenharmony_cienum idlestate_value {
18762306a36Sopenharmony_ci	IDLESTATE_USAGE,
18862306a36Sopenharmony_ci	IDLESTATE_POWER,
18962306a36Sopenharmony_ci	IDLESTATE_LATENCY,
19062306a36Sopenharmony_ci	IDLESTATE_TIME,
19162306a36Sopenharmony_ci	IDLESTATE_DISABLE,
19262306a36Sopenharmony_ci	MAX_IDLESTATE_VALUE_FILES
19362306a36Sopenharmony_ci};
19462306a36Sopenharmony_ci
19562306a36Sopenharmony_cistatic const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
19662306a36Sopenharmony_ci	[IDLESTATE_USAGE] = "usage",
19762306a36Sopenharmony_ci	[IDLESTATE_POWER] = "power",
19862306a36Sopenharmony_ci	[IDLESTATE_LATENCY] = "latency",
19962306a36Sopenharmony_ci	[IDLESTATE_TIME]  = "time",
20062306a36Sopenharmony_ci	[IDLESTATE_DISABLE]  = "disable",
20162306a36Sopenharmony_ci};
20262306a36Sopenharmony_ci
20362306a36Sopenharmony_cistatic unsigned long long sysfs_idlestate_get_one_value(unsigned int cpu,
20462306a36Sopenharmony_ci						     unsigned int idlestate,
20562306a36Sopenharmony_ci						     enum idlestate_value which)
20662306a36Sopenharmony_ci{
20762306a36Sopenharmony_ci	unsigned long long value;
20862306a36Sopenharmony_ci	unsigned int len;
20962306a36Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
21062306a36Sopenharmony_ci	char *endp;
21162306a36Sopenharmony_ci
21262306a36Sopenharmony_ci	if (which >= MAX_IDLESTATE_VALUE_FILES)
21362306a36Sopenharmony_ci		return 0;
21462306a36Sopenharmony_ci
21562306a36Sopenharmony_ci	len = sysfs_idlestate_read_file(cpu, idlestate,
21662306a36Sopenharmony_ci					idlestate_value_files[which],
21762306a36Sopenharmony_ci					linebuf, sizeof(linebuf));
21862306a36Sopenharmony_ci	if (len == 0)
21962306a36Sopenharmony_ci		return 0;
22062306a36Sopenharmony_ci
22162306a36Sopenharmony_ci	value = strtoull(linebuf, &endp, 0);
22262306a36Sopenharmony_ci
22362306a36Sopenharmony_ci	if (endp == linebuf || errno == ERANGE)
22462306a36Sopenharmony_ci		return 0;
22562306a36Sopenharmony_ci
22662306a36Sopenharmony_ci	return value;
22762306a36Sopenharmony_ci}
22862306a36Sopenharmony_ci
22962306a36Sopenharmony_ci/* read access to files which contain one string */
23062306a36Sopenharmony_ci
23162306a36Sopenharmony_cienum idlestate_string {
23262306a36Sopenharmony_ci	IDLESTATE_DESC,
23362306a36Sopenharmony_ci	IDLESTATE_NAME,
23462306a36Sopenharmony_ci	MAX_IDLESTATE_STRING_FILES
23562306a36Sopenharmony_ci};
23662306a36Sopenharmony_ci
23762306a36Sopenharmony_cistatic const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
23862306a36Sopenharmony_ci	[IDLESTATE_DESC] = "desc",
23962306a36Sopenharmony_ci	[IDLESTATE_NAME] = "name",
24062306a36Sopenharmony_ci};
24162306a36Sopenharmony_ci
24262306a36Sopenharmony_ci
24362306a36Sopenharmony_cistatic char *sysfs_idlestate_get_one_string(unsigned int cpu,
24462306a36Sopenharmony_ci					unsigned int idlestate,
24562306a36Sopenharmony_ci					enum idlestate_string which)
24662306a36Sopenharmony_ci{
24762306a36Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
24862306a36Sopenharmony_ci	char *result;
24962306a36Sopenharmony_ci	unsigned int len;
25062306a36Sopenharmony_ci
25162306a36Sopenharmony_ci	if (which >= MAX_IDLESTATE_STRING_FILES)
25262306a36Sopenharmony_ci		return NULL;
25362306a36Sopenharmony_ci
25462306a36Sopenharmony_ci	len = sysfs_idlestate_read_file(cpu, idlestate,
25562306a36Sopenharmony_ci					idlestate_string_files[which],
25662306a36Sopenharmony_ci					linebuf, sizeof(linebuf));
25762306a36Sopenharmony_ci	if (len == 0)
25862306a36Sopenharmony_ci		return NULL;
25962306a36Sopenharmony_ci
26062306a36Sopenharmony_ci	result = strdup(linebuf);
26162306a36Sopenharmony_ci	if (result == NULL)
26262306a36Sopenharmony_ci		return NULL;
26362306a36Sopenharmony_ci
26462306a36Sopenharmony_ci	if (result[strlen(result) - 1] == '\n')
26562306a36Sopenharmony_ci		result[strlen(result) - 1] = '\0';
26662306a36Sopenharmony_ci
26762306a36Sopenharmony_ci	return result;
26862306a36Sopenharmony_ci}
26962306a36Sopenharmony_ci
27062306a36Sopenharmony_ci/*
27162306a36Sopenharmony_ci * Returns:
27262306a36Sopenharmony_ci *    1  if disabled
27362306a36Sopenharmony_ci *    0  if enabled
27462306a36Sopenharmony_ci *    -1 if idlestate is not available
27562306a36Sopenharmony_ci *    -2 if disabling is not supported by the kernel
27662306a36Sopenharmony_ci */
27762306a36Sopenharmony_ciint sysfs_is_idlestate_disabled(unsigned int cpu,
27862306a36Sopenharmony_ci				unsigned int idlestate)
27962306a36Sopenharmony_ci{
28062306a36Sopenharmony_ci	if (sysfs_get_idlestate_count(cpu) <= idlestate)
28162306a36Sopenharmony_ci		return -1;
28262306a36Sopenharmony_ci
28362306a36Sopenharmony_ci	if (!sysfs_idlestate_file_exists(cpu, idlestate,
28462306a36Sopenharmony_ci				 idlestate_value_files[IDLESTATE_DISABLE]))
28562306a36Sopenharmony_ci		return -2;
28662306a36Sopenharmony_ci	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
28762306a36Sopenharmony_ci}
28862306a36Sopenharmony_ci
28962306a36Sopenharmony_ci/*
29062306a36Sopenharmony_ci * Pass 1 as last argument to disable or 0 to enable the state
29162306a36Sopenharmony_ci * Returns:
29262306a36Sopenharmony_ci *    0  on success
29362306a36Sopenharmony_ci *    negative values on error, for example:
29462306a36Sopenharmony_ci *      -1 if idlestate is not available
29562306a36Sopenharmony_ci *      -2 if disabling is not supported by the kernel
29662306a36Sopenharmony_ci *      -3 No write access to disable/enable C-states
29762306a36Sopenharmony_ci */
29862306a36Sopenharmony_ciint sysfs_idlestate_disable(unsigned int cpu,
29962306a36Sopenharmony_ci			    unsigned int idlestate,
30062306a36Sopenharmony_ci			    unsigned int disable)
30162306a36Sopenharmony_ci{
30262306a36Sopenharmony_ci	char value[SYSFS_PATH_MAX];
30362306a36Sopenharmony_ci	int bytes_written;
30462306a36Sopenharmony_ci
30562306a36Sopenharmony_ci	if (sysfs_get_idlestate_count(cpu) <= idlestate)
30662306a36Sopenharmony_ci		return -1;
30762306a36Sopenharmony_ci
30862306a36Sopenharmony_ci	if (!sysfs_idlestate_file_exists(cpu, idlestate,
30962306a36Sopenharmony_ci				 idlestate_value_files[IDLESTATE_DISABLE]))
31062306a36Sopenharmony_ci		return -2;
31162306a36Sopenharmony_ci
31262306a36Sopenharmony_ci	snprintf(value, SYSFS_PATH_MAX, "%u", disable);
31362306a36Sopenharmony_ci
31462306a36Sopenharmony_ci	bytes_written = sysfs_idlestate_write_file(cpu, idlestate, "disable",
31562306a36Sopenharmony_ci						   value, sizeof(disable));
31662306a36Sopenharmony_ci	if (bytes_written)
31762306a36Sopenharmony_ci		return 0;
31862306a36Sopenharmony_ci	return -3;
31962306a36Sopenharmony_ci}
32062306a36Sopenharmony_ci
32162306a36Sopenharmony_ciunsigned long sysfs_get_idlestate_latency(unsigned int cpu,
32262306a36Sopenharmony_ci					  unsigned int idlestate)
32362306a36Sopenharmony_ci{
32462306a36Sopenharmony_ci	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
32562306a36Sopenharmony_ci}
32662306a36Sopenharmony_ci
32762306a36Sopenharmony_ciunsigned long sysfs_get_idlestate_usage(unsigned int cpu,
32862306a36Sopenharmony_ci					unsigned int idlestate)
32962306a36Sopenharmony_ci{
33062306a36Sopenharmony_ci	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
33162306a36Sopenharmony_ci}
33262306a36Sopenharmony_ci
33362306a36Sopenharmony_ciunsigned long long sysfs_get_idlestate_time(unsigned int cpu,
33462306a36Sopenharmony_ci					unsigned int idlestate)
33562306a36Sopenharmony_ci{
33662306a36Sopenharmony_ci	return sysfs_idlestate_get_one_value(cpu, idlestate, IDLESTATE_TIME);
33762306a36Sopenharmony_ci}
33862306a36Sopenharmony_ci
33962306a36Sopenharmony_cichar *sysfs_get_idlestate_name(unsigned int cpu, unsigned int idlestate)
34062306a36Sopenharmony_ci{
34162306a36Sopenharmony_ci	return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_NAME);
34262306a36Sopenharmony_ci}
34362306a36Sopenharmony_ci
34462306a36Sopenharmony_cichar *sysfs_get_idlestate_desc(unsigned int cpu, unsigned int idlestate)
34562306a36Sopenharmony_ci{
34662306a36Sopenharmony_ci	return sysfs_idlestate_get_one_string(cpu, idlestate, IDLESTATE_DESC);
34762306a36Sopenharmony_ci}
34862306a36Sopenharmony_ci
34962306a36Sopenharmony_ci/*
35062306a36Sopenharmony_ci * Returns number of supported C-states of CPU core cpu
35162306a36Sopenharmony_ci * Negativ in error case
35262306a36Sopenharmony_ci * Zero if cpuidle does not export any C-states
35362306a36Sopenharmony_ci */
35462306a36Sopenharmony_ciunsigned int sysfs_get_idlestate_count(unsigned int cpu)
35562306a36Sopenharmony_ci{
35662306a36Sopenharmony_ci	char file[SYSFS_PATH_MAX];
35762306a36Sopenharmony_ci	struct stat statbuf;
35862306a36Sopenharmony_ci	int idlestates = 1;
35962306a36Sopenharmony_ci
36062306a36Sopenharmony_ci
36162306a36Sopenharmony_ci	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
36262306a36Sopenharmony_ci	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
36362306a36Sopenharmony_ci		return 0;
36462306a36Sopenharmony_ci
36562306a36Sopenharmony_ci	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
36662306a36Sopenharmony_ci	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
36762306a36Sopenharmony_ci		return 0;
36862306a36Sopenharmony_ci
36962306a36Sopenharmony_ci	while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
37062306a36Sopenharmony_ci		snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
37162306a36Sopenharmony_ci			 "cpu%u/cpuidle/state%d", cpu, idlestates);
37262306a36Sopenharmony_ci		idlestates++;
37362306a36Sopenharmony_ci	}
37462306a36Sopenharmony_ci	idlestates--;
37562306a36Sopenharmony_ci	return idlestates;
37662306a36Sopenharmony_ci}
37762306a36Sopenharmony_ci
37862306a36Sopenharmony_ci/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
37962306a36Sopenharmony_ci
38062306a36Sopenharmony_ci/*
38162306a36Sopenharmony_ci * helper function to read file from /sys into given buffer
38262306a36Sopenharmony_ci * fname is a relative path under "cpu/cpuidle/" dir
38362306a36Sopenharmony_ci */
38462306a36Sopenharmony_cistatic unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
38562306a36Sopenharmony_ci					    size_t buflen)
38662306a36Sopenharmony_ci{
38762306a36Sopenharmony_ci	char path[SYSFS_PATH_MAX];
38862306a36Sopenharmony_ci
38962306a36Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
39062306a36Sopenharmony_ci
39162306a36Sopenharmony_ci	return sysfs_read_file(path, buf, buflen);
39262306a36Sopenharmony_ci}
39362306a36Sopenharmony_ci
39462306a36Sopenharmony_ci
39562306a36Sopenharmony_ci
39662306a36Sopenharmony_ci/* read access to files which contain one string */
39762306a36Sopenharmony_ci
39862306a36Sopenharmony_cienum cpuidle_string {
39962306a36Sopenharmony_ci	CPUIDLE_GOVERNOR,
40062306a36Sopenharmony_ci	CPUIDLE_GOVERNOR_RO,
40162306a36Sopenharmony_ci	CPUIDLE_DRIVER,
40262306a36Sopenharmony_ci	MAX_CPUIDLE_STRING_FILES
40362306a36Sopenharmony_ci};
40462306a36Sopenharmony_ci
40562306a36Sopenharmony_cistatic const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
40662306a36Sopenharmony_ci	[CPUIDLE_GOVERNOR]	= "current_governor",
40762306a36Sopenharmony_ci	[CPUIDLE_GOVERNOR_RO]	= "current_governor_ro",
40862306a36Sopenharmony_ci	[CPUIDLE_DRIVER]	= "current_driver",
40962306a36Sopenharmony_ci};
41062306a36Sopenharmony_ci
41162306a36Sopenharmony_ci
41262306a36Sopenharmony_cistatic char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
41362306a36Sopenharmony_ci{
41462306a36Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
41562306a36Sopenharmony_ci	char *result;
41662306a36Sopenharmony_ci	unsigned int len;
41762306a36Sopenharmony_ci
41862306a36Sopenharmony_ci	if (which >= MAX_CPUIDLE_STRING_FILES)
41962306a36Sopenharmony_ci		return NULL;
42062306a36Sopenharmony_ci
42162306a36Sopenharmony_ci	len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
42262306a36Sopenharmony_ci				linebuf, sizeof(linebuf));
42362306a36Sopenharmony_ci	if (len == 0)
42462306a36Sopenharmony_ci		return NULL;
42562306a36Sopenharmony_ci
42662306a36Sopenharmony_ci	result = strdup(linebuf);
42762306a36Sopenharmony_ci	if (result == NULL)
42862306a36Sopenharmony_ci		return NULL;
42962306a36Sopenharmony_ci
43062306a36Sopenharmony_ci	if (result[strlen(result) - 1] == '\n')
43162306a36Sopenharmony_ci		result[strlen(result) - 1] = '\0';
43262306a36Sopenharmony_ci
43362306a36Sopenharmony_ci	return result;
43462306a36Sopenharmony_ci}
43562306a36Sopenharmony_ci
43662306a36Sopenharmony_cichar *sysfs_get_cpuidle_governor(void)
43762306a36Sopenharmony_ci{
43862306a36Sopenharmony_ci	char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
43962306a36Sopenharmony_ci	if (!tmp)
44062306a36Sopenharmony_ci		return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
44162306a36Sopenharmony_ci	else
44262306a36Sopenharmony_ci		return tmp;
44362306a36Sopenharmony_ci}
44462306a36Sopenharmony_ci
44562306a36Sopenharmony_cichar *sysfs_get_cpuidle_driver(void)
44662306a36Sopenharmony_ci{
44762306a36Sopenharmony_ci	return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
44862306a36Sopenharmony_ci}
44962306a36Sopenharmony_ci/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
45062306a36Sopenharmony_ci
45162306a36Sopenharmony_ci/*
45262306a36Sopenharmony_ci * Get sched_mc or sched_smt settings
45362306a36Sopenharmony_ci * Pass "mc" or "smt" as argument
45462306a36Sopenharmony_ci *
45562306a36Sopenharmony_ci * Returns negative value on failure
45662306a36Sopenharmony_ci */
45762306a36Sopenharmony_ciint sysfs_get_sched(const char *smt_mc)
45862306a36Sopenharmony_ci{
45962306a36Sopenharmony_ci	return -ENODEV;
46062306a36Sopenharmony_ci}
46162306a36Sopenharmony_ci
46262306a36Sopenharmony_ci/*
46362306a36Sopenharmony_ci * Get sched_mc or sched_smt settings
46462306a36Sopenharmony_ci * Pass "mc" or "smt" as argument
46562306a36Sopenharmony_ci *
46662306a36Sopenharmony_ci * Returns negative value on failure
46762306a36Sopenharmony_ci */
46862306a36Sopenharmony_ciint sysfs_set_sched(const char *smt_mc, int val)
46962306a36Sopenharmony_ci{
47062306a36Sopenharmony_ci	return -ENODEV;
47162306a36Sopenharmony_ci}
472