Orange Pi5 kernel

Deprecated Linux kernel 5.10.110 for OrangePi 5/5B/5+ boards

3 Commits   0 Branches   0 Tags
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   1) // SPDX-License-Identifier: GPL-2.0-only
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   2) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   3)  *  (C) 2004-2009  Dominik Brodowski <linux@dominikbrodowski.de>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   4)  *  (C) 2011       Thomas Renninger <trenn@novell.com> Novell Inc.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   5)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   6) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   7) #include <stdio.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   8) #include <errno.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300   9) #include <stdlib.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  10) #include <string.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  11) #include <sys/types.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  12) #include <sys/stat.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  13) #include <fcntl.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  14) #include <unistd.h>
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  15) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  16) #include "cpuidle.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  17) #include "cpupower_intern.h"
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  18) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  19) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  20)  * helper function to check whether a file under "../cpuX/cpuidle/stateX/" dir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  21)  * exists.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  22)  * For example the functionality to disable c-states was introduced in later
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  23)  * kernel versions, this function can be used to explicitly check for this
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  24)  * feature.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  25)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  26)  * returns 1 if the file exists, 0 otherwise.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  27)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  28) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  29) unsigned int cpuidle_state_file_exists(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  30) 				       unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  31) 				       const char *fname)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  32) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  33) 	char path[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  34) 	struct stat statbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  35) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  36) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  37) 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  38) 		 cpu, idlestate, fname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  39) 	if (stat(path, &statbuf) != 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  40) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  41) 	return 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  42) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  43) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  44) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  45)  * helper function to read file from /sys into given buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  46)  * fname is a relative path under "cpuX/cpuidle/stateX/" dir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  47)  * cstates starting with 0, C0 is not counted as cstate.
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  48)  * This means if you want C1 info, pass 0 as idlestate param
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  49)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  50) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  51) unsigned int cpuidle_state_read_file(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  52) 					    unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  53) 					    const char *fname, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  54) 					    size_t buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  55) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  56) 	char path[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  57) 	int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  58) 	ssize_t numread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  59) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  60) 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  61) 		 cpu, idlestate, fname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  62) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  63) 	fd = open(path, O_RDONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  64) 	if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  65) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  66) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  67) 	numread = read(fd, buf, buflen - 1);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  68) 	if (numread < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  69) 		close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  70) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  71) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  72) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  73) 	buf[numread] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  74) 	close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  75) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  76) 	return (unsigned int) numread;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  77) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  78) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  79) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  80)  * helper function to write a new value to a /sys file
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  81)  * fname is a relative path under "../cpuX/cpuidle/cstateY/" dir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  82)  *
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  83)  * Returns the number of bytes written or 0 on error
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  84)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  85) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  86) unsigned int cpuidle_state_write_file(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  87) 				      unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  88) 				      const char *fname,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  89) 				      const char *value, size_t len)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  90) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  91) 	char path[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  92) 	int fd;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  93) 	ssize_t numwrite;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  94) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  95) 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/cpuidle/state%u/%s",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  96) 		 cpu, idlestate, fname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  97) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  98) 	fd = open(path, O_WRONLY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300  99) 	if (fd == -1)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 100) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 101) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 102) 	numwrite = write(fd, value, len);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 103) 	if (numwrite < 1) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 104) 		close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 105) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 106) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 107) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 108) 	close(fd);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 109) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 110) 	return (unsigned int) numwrite;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 111) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 112) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 113) /* read access to files which contain one numeric value */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 114) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 115) enum idlestate_value {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 116) 	IDLESTATE_USAGE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 117) 	IDLESTATE_POWER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 118) 	IDLESTATE_LATENCY,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 119) 	IDLESTATE_TIME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 120) 	IDLESTATE_DISABLE,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 121) 	MAX_IDLESTATE_VALUE_FILES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 122) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 123) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 124) static const char *idlestate_value_files[MAX_IDLESTATE_VALUE_FILES] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 125) 	[IDLESTATE_USAGE] = "usage",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 126) 	[IDLESTATE_POWER] = "power",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 127) 	[IDLESTATE_LATENCY] = "latency",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 128) 	[IDLESTATE_TIME]  = "time",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 129) 	[IDLESTATE_DISABLE]  = "disable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 130) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 131) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 132) static
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 133) unsigned long long cpuidle_state_get_one_value(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 134) 					       unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 135) 					       enum idlestate_value which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 136) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 137) 	unsigned long long value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 138) 	unsigned int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 139) 	char linebuf[MAX_LINE_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 140) 	char *endp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 141) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 142) 	if (which >= MAX_IDLESTATE_VALUE_FILES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 143) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 144) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 145) 	len = cpuidle_state_read_file(cpu, idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 146) 				      idlestate_value_files[which],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 147) 				      linebuf, sizeof(linebuf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 148) 	if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 149) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 150) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 151) 	value = strtoull(linebuf, &endp, 0);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 152) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 153) 	if (endp == linebuf || errno == ERANGE)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 154) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 155) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 156) 	return value;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 157) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 158) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 159) /* read access to files which contain one string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 160) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 161) enum idlestate_string {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 162) 	IDLESTATE_DESC,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 163) 	IDLESTATE_NAME,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 164) 	MAX_IDLESTATE_STRING_FILES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 165) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 166) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 167) static const char *idlestate_string_files[MAX_IDLESTATE_STRING_FILES] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 168) 	[IDLESTATE_DESC] = "desc",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 169) 	[IDLESTATE_NAME] = "name",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 170) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 171) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 172) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 173) static char *cpuidle_state_get_one_string(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 174) 					unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 175) 					enum idlestate_string which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 176) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 177) 	char linebuf[MAX_LINE_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 178) 	char *result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 179) 	unsigned int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 180) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 181) 	if (which >= MAX_IDLESTATE_STRING_FILES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 182) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 183) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 184) 	len = cpuidle_state_read_file(cpu, idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 185) 				      idlestate_string_files[which],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 186) 				      linebuf, sizeof(linebuf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 187) 	if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 188) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 189) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 190) 	result = strdup(linebuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 191) 	if (result == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 192) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 193) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 194) 	if (result[strlen(result) - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 195) 		result[strlen(result) - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 196) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 197) 	return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 198) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 199) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 200) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 201)  * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 202)  *    1  if disabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 203)  *    0  if enabled
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 204)  *    -1 if idlestate is not available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 205)  *    -2 if disabling is not supported by the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 206)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 207) int cpuidle_is_state_disabled(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 208) 				unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 209) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 210) 	if (cpuidle_state_count(cpu) <= idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 211) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 212) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 213) 	if (!cpuidle_state_file_exists(cpu, idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 214) 				 idlestate_value_files[IDLESTATE_DISABLE]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 215) 		return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 216) 	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_DISABLE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 217) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 218) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 219) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 220)  * Pass 1 as last argument to disable or 0 to enable the state
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 221)  * Returns:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 222)  *    0  on success
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 223)  *    negative values on error, for example:
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 224)  *      -1 if idlestate is not available
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 225)  *      -2 if disabling is not supported by the kernel
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 226)  *      -3 No write access to disable/enable C-states
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 227)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 228) int cpuidle_state_disable(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 229) 			    unsigned int idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 230) 			    unsigned int disable)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 231) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 232) 	char value[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 233) 	int bytes_written;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 234) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 235) 	if (cpuidle_state_count(cpu) <= idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 236) 		return -1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 237) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 238) 	if (!cpuidle_state_file_exists(cpu, idlestate,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 239) 				 idlestate_value_files[IDLESTATE_DISABLE]))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 240) 		return -2;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 241) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 242) 	snprintf(value, SYSFS_PATH_MAX, "%u", disable);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 243) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 244) 	bytes_written = cpuidle_state_write_file(cpu, idlestate, "disable",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 245) 						   value, sizeof(disable));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 246) 	if (bytes_written)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 247) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 248) 	return -3;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 249) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 250) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 251) unsigned long cpuidle_state_latency(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 252) 					  unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 253) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 254) 	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_LATENCY);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 255) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 256) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 257) unsigned long cpuidle_state_usage(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 258) 					unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 259) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 260) 	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_USAGE);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 261) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 262) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 263) unsigned long long cpuidle_state_time(unsigned int cpu,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 264) 					unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 265) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 266) 	return cpuidle_state_get_one_value(cpu, idlestate, IDLESTATE_TIME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 267) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 268) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 269) char *cpuidle_state_name(unsigned int cpu, unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 270) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 271) 	return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_NAME);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 272) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 273) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 274) char *cpuidle_state_desc(unsigned int cpu, unsigned int idlestate)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 275) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 276) 	return cpuidle_state_get_one_string(cpu, idlestate, IDLESTATE_DESC);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 277) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 278) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 279) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 280)  * Returns number of supported C-states of CPU core cpu
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 281)  * Negativ in error case
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 282)  * Zero if cpuidle does not export any C-states
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 283)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 284) unsigned int cpuidle_state_count(unsigned int cpu)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 285) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 286) 	char file[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 287) 	struct stat statbuf;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 288) 	int idlestates = 1;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 289) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 290) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 291) 	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpuidle");
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 292) 	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 293) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 294) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 295) 	snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU "cpu%u/cpuidle/state0", cpu);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 296) 	if (stat(file, &statbuf) != 0 || !S_ISDIR(statbuf.st_mode))
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 297) 		return 0;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 298) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 299) 	while (stat(file, &statbuf) == 0 && S_ISDIR(statbuf.st_mode)) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 300) 		snprintf(file, SYSFS_PATH_MAX, PATH_TO_CPU
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 301) 			 "cpu%u/cpuidle/state%d", cpu, idlestates);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 302) 		idlestates++;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 303) 	}
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 304) 	idlestates--;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 305) 	return idlestates;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 306) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 307) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 308) /* CPUidle general /sys/devices/system/cpu/cpuidle/ sysfs access ********/
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 309) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 310) /*
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 311)  * helper function to read file from /sys into given buffer
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 312)  * fname is a relative path under "cpu/cpuidle/" dir
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 313)  */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 314) static unsigned int sysfs_cpuidle_read_file(const char *fname, char *buf,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 315) 					    size_t buflen)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 316) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 317) 	char path[SYSFS_PATH_MAX];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 318) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 319) 	snprintf(path, sizeof(path), PATH_TO_CPU "cpuidle/%s", fname);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 320) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 321) 	return cpupower_read_sysfs(path, buf, buflen);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 322) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 323) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 324) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 325) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 326) /* read access to files which contain one string */
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 327) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 328) enum cpuidle_string {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 329) 	CPUIDLE_GOVERNOR,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 330) 	CPUIDLE_GOVERNOR_RO,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 331) 	CPUIDLE_DRIVER,
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 332) 	MAX_CPUIDLE_STRING_FILES
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 333) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 334) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 335) static const char *cpuidle_string_files[MAX_CPUIDLE_STRING_FILES] = {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 336) 	[CPUIDLE_GOVERNOR]	= "current_governor",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 337) 	[CPUIDLE_GOVERNOR_RO]	= "current_governor_ro",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 338) 	[CPUIDLE_DRIVER]	= "current_driver",
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 339) };
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 340) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 341) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 342) static char *sysfs_cpuidle_get_one_string(enum cpuidle_string which)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 343) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 344) 	char linebuf[MAX_LINE_LEN];
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 345) 	char *result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 346) 	unsigned int len;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 347) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 348) 	if (which >= MAX_CPUIDLE_STRING_FILES)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 349) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 350) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 351) 	len = sysfs_cpuidle_read_file(cpuidle_string_files[which],
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 352) 				linebuf, sizeof(linebuf));
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 353) 	if (len == 0)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 354) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 355) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 356) 	result = strdup(linebuf);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 357) 	if (result == NULL)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 358) 		return NULL;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 359) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 360) 	if (result[strlen(result) - 1] == '\n')
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 361) 		result[strlen(result) - 1] = '\0';
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 362) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 363) 	return result;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 364) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 365) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 366) char *cpuidle_get_governor(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 367) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 368) 	char *tmp = sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR_RO);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 369) 	if (!tmp)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 370) 		return sysfs_cpuidle_get_one_string(CPUIDLE_GOVERNOR);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 371) 	else
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 372) 		return tmp;
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 373) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 374) 
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 375) char *cpuidle_get_driver(void)
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 376) {
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 377) 	return sysfs_cpuidle_get_one_string(CPUIDLE_DRIVER);
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 378) }
^8f3ce5b39 (kx 2023-10-28 12:00:06 +0300 379) /* CPUidle idlestate specific /sys/devices/system/cpu/cpuX/cpuidle/ access */