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