18c2ecf20Sopenharmony_ci// SPDX-License-Identifier: GPL-2.0-only
28c2ecf20Sopenharmony_ci/*
38c2ecf20Sopenharmony_ci *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
48c2ecf20Sopenharmony_ci *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
58c2ecf20Sopenharmony_ci */
68c2ecf20Sopenharmony_ci
78c2ecf20Sopenharmony_ci#include <stdio.h>
88c2ecf20Sopenharmony_ci#include <errno.h>
98c2ecf20Sopenharmony_ci#include <stdlib.h>
108c2ecf20Sopenharmony_ci#include <string.h>
118c2ecf20Sopenharmony_ci#include <sys/types.h>
128c2ecf20Sopenharmony_ci#include <sys/stat.h>
138c2ecf20Sopenharmony_ci#include <fcntl.h>
148c2ecf20Sopenharmony_ci#include <unistd.h>
158c2ecf20Sopenharmony_ci
168c2ecf20Sopenharmony_ci#include "cpuidle.h"
178c2ecf20Sopenharmony_ci#include "cpupower_intern.h"
188c2ecf20Sopenharmony_ci
198c2ecf20Sopenharmony_ci/*
208c2ecf20Sopenharmony_ci * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
218c2ecf20Sopenharmony_ci * exists.
228c2ecf20Sopenharmony_ci * For example the functionality to disable c-states was introduced in later
238c2ecf20Sopenharmony_ci * kernel versions, this function can be used to explicitly check for this
248c2ecf20Sopenharmony_ci * feature.
258c2ecf20Sopenharmony_ci *
268c2ecf20Sopenharmony_ci * returns 1 if the file exists, 0 otherwise.
278c2ecf20Sopenharmony_ci */
288c2ecf20Sopenharmony_cistatic
298c2ecf20Sopenharmony_ciunsigned int cpuidle_state_file_exists(unsigned int cpu,
308c2ecf20Sopenharmony_ci				       unsigned int idlestate,
318c2ecf20Sopenharmony_ci				       const char *fname)
328c2ecf20Sopenharmony_ci{
338c2ecf20Sopenharmony_ci	char path[SYSFS_PATH_MAX];
348c2ecf20Sopenharmony_ci	struct stat statbuf;
358c2ecf20Sopenharmony_ci
368c2ecf20Sopenharmony_ci
378c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
388c2ecf20Sopenharmony_ci		 cpu, idlestate, fname);
398c2ecf20Sopenharmony_ci	if (stat(path, &statbuf) != 0)
408c2ecf20Sopenharmony_ci		return 0;
418c2ecf20Sopenharmony_ci	return 1;
428c2ecf20Sopenharmony_ci}
438c2ecf20Sopenharmony_ci
448c2ecf20Sopenharmony_ci/*
458c2ecf20Sopenharmony_ci * helper function to read file from /sys into given buffer
468c2ecf20Sopenharmony_ci * fname is a relative path under "cpuX/cpuidle/stateX/" dir
478c2ecf20Sopenharmony_ci * cstates starting with 0, C0 is not counted as cstate.
488c2ecf20Sopenharmony_ci * This means if you want C1 info, pass 0 as idlestate param
498c2ecf20Sopenharmony_ci */
508c2ecf20Sopenharmony_cistatic
518c2ecf20Sopenharmony_ciunsigned int cpuidle_state_read_file(unsigned int cpu,
528c2ecf20Sopenharmony_ci					    unsigned int idlestate,
538c2ecf20Sopenharmony_ci					    const char *fname, char *buf,
548c2ecf20Sopenharmony_ci					    size_t buflen)
558c2ecf20Sopenharmony_ci{
568c2ecf20Sopenharmony_ci	char path[SYSFS_PATH_MAX];
578c2ecf20Sopenharmony_ci	int fd;
588c2ecf20Sopenharmony_ci	ssize_t numread;
598c2ecf20Sopenharmony_ci
608c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
618c2ecf20Sopenharmony_ci		 cpu, idlestate, fname);
628c2ecf20Sopenharmony_ci
638c2ecf20Sopenharmony_ci	fd = open(path, O_RDONLY);
648c2ecf20Sopenharmony_ci	if (fd == -1)
658c2ecf20Sopenharmony_ci		return 0;
668c2ecf20Sopenharmony_ci
678c2ecf20Sopenharmony_ci	numread = read(fd, buf, buflen - 1);
688c2ecf20Sopenharmony_ci	if (numread < 1) {
698c2ecf20Sopenharmony_ci		close(fd);
708c2ecf20Sopenharmony_ci		return 0;
718c2ecf20Sopenharmony_ci	}
728c2ecf20Sopenharmony_ci
738c2ecf20Sopenharmony_ci	buf[numread] = '\0';
748c2ecf20Sopenharmony_ci	close(fd);
758c2ecf20Sopenharmony_ci
768c2ecf20Sopenharmony_ci	return (unsigned int) numread;
778c2ecf20Sopenharmony_ci}
788c2ecf20Sopenharmony_ci
798c2ecf20Sopenharmony_ci/*
808c2ecf20Sopenharmony_ci * helper function to write a new value to a /sys file
818c2ecf20Sopenharmony_ci * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
828c2ecf20Sopenharmony_ci *
838c2ecf20Sopenharmony_ci * Returns the number of bytes written or 0 on error
848c2ecf20Sopenharmony_ci */
858c2ecf20Sopenharmony_cistatic
868c2ecf20Sopenharmony_ciunsigned int cpuidle_state_write_file(unsigned int cpu,
878c2ecf20Sopenharmony_ci				      unsigned int idlestate,
888c2ecf20Sopenharmony_ci				      const char *fname,
898c2ecf20Sopenharmony_ci				      const char *value, size_t len)
908c2ecf20Sopenharmony_ci{
918c2ecf20Sopenharmony_ci	char path[SYSFS_PATH_MAX];
928c2ecf20Sopenharmony_ci	int fd;
938c2ecf20Sopenharmony_ci	ssize_t numwrite;
948c2ecf20Sopenharmony_ci
958c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
968c2ecf20Sopenharmony_ci		 cpu, idlestate, fname);
978c2ecf20Sopenharmony_ci
988c2ecf20Sopenharmony_ci	fd = open(path, O_WRONLY);
998c2ecf20Sopenharmony_ci	if (fd == -1)
1008c2ecf20Sopenharmony_ci		return 0;
1018c2ecf20Sopenharmony_ci
1028c2ecf20Sopenharmony_ci	numwrite = write(fd, value, len);
1038c2ecf20Sopenharmony_ci	if (numwrite < 1) {
1048c2ecf20Sopenharmony_ci		close(fd);
1058c2ecf20Sopenharmony_ci		return 0;
1068c2ecf20Sopenharmony_ci	}
1078c2ecf20Sopenharmony_ci
1088c2ecf20Sopenharmony_ci	close(fd);
1098c2ecf20Sopenharmony_ci
1108c2ecf20Sopenharmony_ci	return (unsigned int) numwrite;
1118c2ecf20Sopenharmony_ci}
1128c2ecf20Sopenharmony_ci
1138c2ecf20Sopenharmony_ci/* read access to files which contain one numeric value */
1148c2ecf20Sopenharmony_ci
1158c2ecf20Sopenharmony_cienum idlestate_value {
1168c2ecf20Sopenharmony_ci	IDLESTATE_USAGE,
1178c2ecf20Sopenharmony_ci	IDLESTATE_POWER,
1188c2ecf20Sopenharmony_ci	IDLESTATE_LATENCY,
1198c2ecf20Sopenharmony_ci	IDLESTATE_TIME,
1208c2ecf20Sopenharmony_ci	IDLESTATE_DISABLE,
1218c2ecf20Sopenharmony_ci	MAX_IDLESTATE_VALUE_FILES
1228c2ecf20Sopenharmony_ci};
1238c2ecf20Sopenharmony_ci
1248c2ecf20Sopenharmony_cistatic const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
1258c2ecf20Sopenharmony_ci	[IDLESTATE_USAGE] = "usage",
1268c2ecf20Sopenharmony_ci	[IDLESTATE_POWER] = "power",
1278c2ecf20Sopenharmony_ci	[IDLESTATE_LATENCY] = "latency",
1288c2ecf20Sopenharmony_ci	[IDLESTATE_TIME]  = "time",
1298c2ecf20Sopenharmony_ci	[IDLESTATE_DISABLE]  = "disable",
1308c2ecf20Sopenharmony_ci};
1318c2ecf20Sopenharmony_ci
1328c2ecf20Sopenharmony_cistatic
1338c2ecf20Sopenharmony_ciunsigned long long cpuidle_state_get_one_value(unsigned int cpu,
1348c2ecf20Sopenharmony_ci					       unsigned int idlestate,
1358c2ecf20Sopenharmony_ci					       enum idlestate_value which)
1368c2ecf20Sopenharmony_ci{
1378c2ecf20Sopenharmony_ci	unsigned long long value;
1388c2ecf20Sopenharmony_ci	unsigned int len;
1398c2ecf20Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
1408c2ecf20Sopenharmony_ci	char *endp;
1418c2ecf20Sopenharmony_ci
1428c2ecf20Sopenharmony_ci	if (which >= MAX_IDLESTATE_VALUE_FILES)
1438c2ecf20Sopenharmony_ci		return 0;
1448c2ecf20Sopenharmony_ci
1458c2ecf20Sopenharmony_ci	len = cpuidle_state_read_file(cpu, idlestate,
1468c2ecf20Sopenharmony_ci				      idlestate_value_files[which],
1478c2ecf20Sopenharmony_ci				      linebuf, sizeof(linebuf));
1488c2ecf20Sopenharmony_ci	if (len == 0)
1498c2ecf20Sopenharmony_ci		return 0;
1508c2ecf20Sopenharmony_ci
1518c2ecf20Sopenharmony_ci	value = strtoull(linebuf, &endp, 0);
1528c2ecf20Sopenharmony_ci
1538c2ecf20Sopenharmony_ci	if (endp == linebuf || errno == ERANGE)
1548c2ecf20Sopenharmony_ci		return 0;
1558c2ecf20Sopenharmony_ci
1568c2ecf20Sopenharmony_ci	return value;
1578c2ecf20Sopenharmony_ci}
1588c2ecf20Sopenharmony_ci
1598c2ecf20Sopenharmony_ci/* read access to files which contain one string */
1608c2ecf20Sopenharmony_ci
1618c2ecf20Sopenharmony_cienum idlestate_string {
1628c2ecf20Sopenharmony_ci	IDLESTATE_DESC,
1638c2ecf20Sopenharmony_ci	IDLESTATE_NAME,
1648c2ecf20Sopenharmony_ci	MAX_IDLESTATE_STRING_FILES
1658c2ecf20Sopenharmony_ci};
1668c2ecf20Sopenharmony_ci
1678c2ecf20Sopenharmony_cistatic const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
1688c2ecf20Sopenharmony_ci	[IDLESTATE_DESC] = "desc",
1698c2ecf20Sopenharmony_ci	[IDLESTATE_NAME] = "name",
1708c2ecf20Sopenharmony_ci};
1718c2ecf20Sopenharmony_ci
1728c2ecf20Sopenharmony_ci
1738c2ecf20Sopenharmony_cistatic char *cpuidle_state_get_one_string(unsigned int cpu,
1748c2ecf20Sopenharmony_ci					unsigned int idlestate,
1758c2ecf20Sopenharmony_ci					enum idlestate_string which)
1768c2ecf20Sopenharmony_ci{
1778c2ecf20Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
1788c2ecf20Sopenharmony_ci	char *result;
1798c2ecf20Sopenharmony_ci	unsigned int len;
1808c2ecf20Sopenharmony_ci
1818c2ecf20Sopenharmony_ci	if (which >= MAX_IDLESTATE_STRING_FILES)
1828c2ecf20Sopenharmony_ci		return NULL;
1838c2ecf20Sopenharmony_ci
1848c2ecf20Sopenharmony_ci	len = cpuidle_state_read_file(cpu, idlestate,
1858c2ecf20Sopenharmony_ci				      idlestate_string_files[which],
1868c2ecf20Sopenharmony_ci				      linebuf, sizeof(linebuf));
1878c2ecf20Sopenharmony_ci	if (len == 0)
1888c2ecf20Sopenharmony_ci		return NULL;
1898c2ecf20Sopenharmony_ci
1908c2ecf20Sopenharmony_ci	result = strdup(linebuf);
1918c2ecf20Sopenharmony_ci	if (result == NULL)
1928c2ecf20Sopenharmony_ci		return NULL;
1938c2ecf20Sopenharmony_ci
1948c2ecf20Sopenharmony_ci	if (result[strlen(result) - 1] == '\n')
1958c2ecf20Sopenharmony_ci		result[strlen(result) - 1] = '\0';
1968c2ecf20Sopenharmony_ci
1978c2ecf20Sopenharmony_ci	return result;
1988c2ecf20Sopenharmony_ci}
1998c2ecf20Sopenharmony_ci
2008c2ecf20Sopenharmony_ci/*
2018c2ecf20Sopenharmony_ci * Returns:
2028c2ecf20Sopenharmony_ci *    1  if disabled
2038c2ecf20Sopenharmony_ci *    0  if enabled
2048c2ecf20Sopenharmony_ci *    -1 if idlestate is not available
2058c2ecf20Sopenharmony_ci *    -2 if disabling is not supported by the kernel
2068c2ecf20Sopenharmony_ci */
2078c2ecf20Sopenharmony_ciint cpuidle_is_state_disabled(unsigned int cpu,
2088c2ecf20Sopenharmony_ci				unsigned int idlestate)
2098c2ecf20Sopenharmony_ci{
2108c2ecf20Sopenharmony_ci	if (cpuidle_state_count(cpu) <= idlestate)
2118c2ecf20Sopenharmony_ci		return -1;
2128c2ecf20Sopenharmony_ci
2138c2ecf20Sopenharmony_ci	if (!cpuidle_state_file_exists(cpu, idlestate,
2148c2ecf20Sopenharmony_ci				 idlestate_value_files[IDLESTATE_DISABLE]))
2158c2ecf20Sopenharmony_ci		return -2;
2168c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
2178c2ecf20Sopenharmony_ci}
2188c2ecf20Sopenharmony_ci
2198c2ecf20Sopenharmony_ci/*
2208c2ecf20Sopenharmony_ci * Pass 1 as last argument to disable or 0 to enable the state
2218c2ecf20Sopenharmony_ci * Returns:
2228c2ecf20Sopenharmony_ci *    0  on success
2238c2ecf20Sopenharmony_ci *    negative values on error, for example:
2248c2ecf20Sopenharmony_ci *      -1 if idlestate is not available
2258c2ecf20Sopenharmony_ci *      -2 if disabling is not supported by the kernel
2268c2ecf20Sopenharmony_ci *      -3 No write access to disable/enable C-states
2278c2ecf20Sopenharmony_ci */
2288c2ecf20Sopenharmony_ciint cpuidle_state_disable(unsigned int cpu,
2298c2ecf20Sopenharmony_ci			    unsigned int idlestate,
2308c2ecf20Sopenharmony_ci			    unsigned int disable)
2318c2ecf20Sopenharmony_ci{
2328c2ecf20Sopenharmony_ci	char value[SYSFS_PATH_MAX];
2338c2ecf20Sopenharmony_ci	int bytes_written;
2348c2ecf20Sopenharmony_ci
2358c2ecf20Sopenharmony_ci	if (cpuidle_state_count(cpu) <= idlestate)
2368c2ecf20Sopenharmony_ci		return -1;
2378c2ecf20Sopenharmony_ci
2388c2ecf20Sopenharmony_ci	if (!cpuidle_state_file_exists(cpu, idlestate,
2398c2ecf20Sopenharmony_ci				 idlestate_value_files[IDLESTATE_DISABLE]))
2408c2ecf20Sopenharmony_ci		return -2;
2418c2ecf20Sopenharmony_ci
2428c2ecf20Sopenharmony_ci	snprintf(value, SYSFS_PATH_MAX, "%u", disable);
2438c2ecf20Sopenharmony_ci
2448c2ecf20Sopenharmony_ci	bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable",
2458c2ecf20Sopenharmony_ci						   value, sizeof(disable));
2468c2ecf20Sopenharmony_ci	if (bytes_written)
2478c2ecf20Sopenharmony_ci		return 0;
2488c2ecf20Sopenharmony_ci	return -3;
2498c2ecf20Sopenharmony_ci}
2508c2ecf20Sopenharmony_ci
2518c2ecf20Sopenharmony_ciunsigned long cpuidle_state_latency(unsigned int cpu,
2528c2ecf20Sopenharmony_ci					  unsigned int idlestate)
2538c2ecf20Sopenharmony_ci{
2548c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
2558c2ecf20Sopenharmony_ci}
2568c2ecf20Sopenharmony_ci
2578c2ecf20Sopenharmony_ciunsigned long cpuidle_state_usage(unsigned int cpu,
2588c2ecf20Sopenharmony_ci					unsigned int idlestate)
2598c2ecf20Sopenharmony_ci{
2608c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
2618c2ecf20Sopenharmony_ci}
2628c2ecf20Sopenharmony_ci
2638c2ecf20Sopenharmony_ciunsigned long long cpuidle_state_time(unsigned int cpu,
2648c2ecf20Sopenharmony_ci					unsigned int idlestate)
2658c2ecf20Sopenharmony_ci{
2668c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME);
2678c2ecf20Sopenharmony_ci}
2688c2ecf20Sopenharmony_ci
2698c2ecf20Sopenharmony_cichar *cpuidle_state_name(unsigned int cpu, unsigned int idlestate)
2708c2ecf20Sopenharmony_ci{
2718c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME);
2728c2ecf20Sopenharmony_ci}
2738c2ecf20Sopenharmony_ci
2748c2ecf20Sopenharmony_cichar *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate)
2758c2ecf20Sopenharmony_ci{
2768c2ecf20Sopenharmony_ci	return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC);
2778c2ecf20Sopenharmony_ci}
2788c2ecf20Sopenharmony_ci
2798c2ecf20Sopenharmony_ci/*
2808c2ecf20Sopenharmony_ci * Returns number of supported C-states of CPU core cpu
2818c2ecf20Sopenharmony_ci * Negativ in error case
2828c2ecf20Sopenharmony_ci * Zero if cpuidle does not export any C-states
2838c2ecf20Sopenharmony_ci */
2848c2ecf20Sopenharmony_ciunsigned int cpuidle_state_count(unsigned int cpu)
2858c2ecf20Sopenharmony_ci{
2868c2ecf20Sopenharmony_ci	char file[SYSFS_PATH_MAX];
2878c2ecf20Sopenharmony_ci	struct stat statbuf;
2888c2ecf20Sopenharmony_ci	int idlestates = 1;
2898c2ecf20Sopenharmony_ci
2908c2ecf20Sopenharmony_ci
2918c2ecf20Sopenharmony_ci	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
2928c2ecf20Sopenharmony_ci	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
2938c2ecf20Sopenharmony_ci		return 0;
2948c2ecf20Sopenharmony_ci
2958c2ecf20Sopenharmony_ci	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
2968c2ecf20Sopenharmony_ci	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
2978c2ecf20Sopenharmony_ci		return 0;
2988c2ecf20Sopenharmony_ci
2998c2ecf20Sopenharmony_ci	while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
3008c2ecf20Sopenharmony_ci		snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
3018c2ecf20Sopenharmony_ci			 "cpu%u/cpuidle/state%d", cpu, idlestates);
3028c2ecf20Sopenharmony_ci		idlestates++;
3038c2ecf20Sopenharmony_ci	}
3048c2ecf20Sopenharmony_ci	idlestates--;
3058c2ecf20Sopenharmony_ci	return idlestates;
3068c2ecf20Sopenharmony_ci}
3078c2ecf20Sopenharmony_ci
3088c2ecf20Sopenharmony_ci/* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
3098c2ecf20Sopenharmony_ci
3108c2ecf20Sopenharmony_ci/*
3118c2ecf20Sopenharmony_ci * helper function to read file from /sys into given buffer
3128c2ecf20Sopenharmony_ci * fname is a relative path under "cpu/cpuidle/" dir
3138c2ecf20Sopenharmony_ci */
3148c2ecf20Sopenharmony_cistatic unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
3158c2ecf20Sopenharmony_ci					    size_t buflen)
3168c2ecf20Sopenharmony_ci{
3178c2ecf20Sopenharmony_ci	char path[SYSFS_PATH_MAX];
3188c2ecf20Sopenharmony_ci
3198c2ecf20Sopenharmony_ci	snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
3208c2ecf20Sopenharmony_ci
3218c2ecf20Sopenharmony_ci	return cpupower_read_sysfs(path, buf, buflen);
3228c2ecf20Sopenharmony_ci}
3238c2ecf20Sopenharmony_ci
3248c2ecf20Sopenharmony_ci
3258c2ecf20Sopenharmony_ci
3268c2ecf20Sopenharmony_ci/* read access to files which contain one string */
3278c2ecf20Sopenharmony_ci
3288c2ecf20Sopenharmony_cienum cpuidle_string {
3298c2ecf20Sopenharmony_ci	CPUIDLE_GOVERNOR,
3308c2ecf20Sopenharmony_ci	CPUIDLE_GOVERNOR_RO,
3318c2ecf20Sopenharmony_ci	CPUIDLE_DRIVER,
3328c2ecf20Sopenharmony_ci	MAX_CPUIDLE_STRING_FILES
3338c2ecf20Sopenharmony_ci};
3348c2ecf20Sopenharmony_ci
3358c2ecf20Sopenharmony_cistatic const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
3368c2ecf20Sopenharmony_ci	[CPUIDLE_GOVERNOR]	= "current_governor",
3378c2ecf20Sopenharmony_ci	[CPUIDLE_GOVERNOR_RO]	= "current_governor_ro",
3388c2ecf20Sopenharmony_ci	[CPUIDLE_DRIVER]	= "current_driver",
3398c2ecf20Sopenharmony_ci};
3408c2ecf20Sopenharmony_ci
3418c2ecf20Sopenharmony_ci
3428c2ecf20Sopenharmony_cistatic char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
3438c2ecf20Sopenharmony_ci{
3448c2ecf20Sopenharmony_ci	char linebuf[MAX_LINE_LEN];
3458c2ecf20Sopenharmony_ci	char *result;
3468c2ecf20Sopenharmony_ci	unsigned int len;
3478c2ecf20Sopenharmony_ci
3488c2ecf20Sopenharmony_ci	if (which >= MAX_CPUIDLE_STRING_FILES)
3498c2ecf20Sopenharmony_ci		return NULL;
3508c2ecf20Sopenharmony_ci
3518c2ecf20Sopenharmony_ci	len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
3528c2ecf20Sopenharmony_ci				linebuf, sizeof(linebuf));
3538c2ecf20Sopenharmony_ci	if (len == 0)
3548c2ecf20Sopenharmony_ci		return NULL;
3558c2ecf20Sopenharmony_ci
3568c2ecf20Sopenharmony_ci	result = strdup(linebuf);
3578c2ecf20Sopenharmony_ci	if (result == NULL)
3588c2ecf20Sopenharmony_ci		return NULL;
3598c2ecf20Sopenharmony_ci
3608c2ecf20Sopenharmony_ci	if (result[strlen(result) - 1] == '\n')
3618c2ecf20Sopenharmony_ci		result[strlen(result) - 1] = '\0';
3628c2ecf20Sopenharmony_ci
3638c2ecf20Sopenharmony_ci	return result;
3648c2ecf20Sopenharmony_ci}
3658c2ecf20Sopenharmony_ci
3668c2ecf20Sopenharmony_cichar *cpuidle_get_governor(void)
3678c2ecf20Sopenharmony_ci{
3688c2ecf20Sopenharmony_ci	char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
3698c2ecf20Sopenharmony_ci	if (!tmp)
3708c2ecf20Sopenharmony_ci		return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
3718c2ecf20Sopenharmony_ci	else
3728c2ecf20Sopenharmony_ci		return tmp;
3738c2ecf20Sopenharmony_ci}
3748c2ecf20Sopenharmony_ci
3758c2ecf20Sopenharmony_cichar *cpuidle_get_driver(void)
3768c2ecf20Sopenharmony_ci{
3778c2ecf20Sopenharmony_ci	return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
3788c2ecf20Sopenharmony_ci}
3798c2ecf20Sopenharmony_ci/* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */
380