^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 */