1 // SPDX-License-Identifier: GPL-2.0 2 3 #include <stdio.h> 4 #include <errno.h> 5 #include <stdlib.h> 6 #include <string.h> 7 8 #include "helpers/helpers.h" 9 #include "helpers/sysfs.h" 10 #include "cpufreq.h" 11 #include "cpupower_intern.h" 12 13 #if defined(__i386__) || defined(__x86_64__) 14 15 #define MSR_AMD_HWCR 0xc0010015 16 17 int cpufreq_has_x86_boost_support(unsigned int cpu, int *support, int *active, 18 int *states) 19 { 20 int ret; 21 unsigned long long val; 22 char linebuf[MAX_LINE_LEN]; 23 char path[SYSFS_PATH_MAX]; 24 char *endp; 25 26 *support = *active = *states = 0; 27 28 if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CPB) { 29 *support = 1; 30 31 /* AMD Family 0x17 does not utilize PCI D18F4 like prior 32 * families and has no fixed discrete boost states but 33 * has Hardware determined variable increments instead. 34 */ 35 36 if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CPB_MSR) { 37 if (!read_msr(cpu, MSR_AMD_HWCR, &val)) { 38 if (!(val & CPUPOWER_AMD_CPBDIS)) 39 *active = 1; 40 } 41 } else { 42 ret = amd_pci_get_num_boost_states(active, states); 43 if (ret) 44 return ret; 45 } 46 } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) { 47 amd_pstate_boost_init(cpu, support, active); 48 } else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA) { 49 *support = *active = 1; 50 51 snprintf(path, sizeof(path), PATH_TO_CPU "intel_pstate/no_turbo"); 52 53 if (!is_valid_path(path)) 54 return 0; 55 56 if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0) 57 return -1; 58 59 val = strtol(linebuf, &endp, 0); 60 if (endp == linebuf || errno == ERANGE) 61 return -1; 62 63 *active = !val; 64 } 65 return 0; 66 } 67 68 int cpupower_set_intel_turbo_boost(int turbo_boost) 69 { 70 char path[SYSFS_PATH_MAX]; 71 char linebuf[2] = {}; 72 73 snprintf(path, sizeof(path), PATH_TO_CPU "intel_pstate/no_turbo"); 74 75 /* Fallback to generic solution when intel_pstate driver not running */ 76 if (!is_valid_path(path)) 77 return cpupower_set_generic_turbo_boost(turbo_boost); 78 79 snprintf(linebuf, sizeof(linebuf), "%d", !turbo_boost); 80 81 if (cpupower_write_sysfs(path, linebuf, 2) <= 0) 82 return -1; 83 84 return 0; 85 } 86 87 int cpupower_intel_get_perf_bias(unsigned int cpu) 88 { 89 char linebuf[MAX_LINE_LEN]; 90 char path[SYSFS_PATH_MAX]; 91 unsigned long val; 92 char *endp; 93 94 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) 95 return -1; 96 97 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu); 98 99 if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0) 100 return -1; 101 102 val = strtol(linebuf, &endp, 0); 103 if (endp == linebuf || errno == ERANGE) 104 return -1; 105 106 return val; 107 } 108 109 int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val) 110 { 111 char path[SYSFS_PATH_MAX]; 112 char linebuf[3] = {}; 113 114 if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS)) 115 return -1; 116 117 snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu); 118 snprintf(linebuf, sizeof(linebuf), "%d", val); 119 120 if (cpupower_write_sysfs(path, linebuf, 3) <= 0) 121 return -1; 122 123 return 0; 124 } 125 126 int cpupower_set_epp(unsigned int cpu, char *epp) 127 { 128 char path[SYSFS_PATH_MAX]; 129 char linebuf[30] = {}; 130 131 snprintf(path, sizeof(path), 132 PATH_TO_CPU "cpu%u/cpufreq/energy_performance_preference", cpu); 133 134 if (!is_valid_path(path)) 135 return -1; 136 137 snprintf(linebuf, sizeof(linebuf), "%s", epp); 138 139 if (cpupower_write_sysfs(path, linebuf, 30) <= 0) 140 return -1; 141 142 return 0; 143 } 144 145 int cpupower_set_amd_pstate_mode(char *mode) 146 { 147 char path[SYSFS_PATH_MAX]; 148 char linebuf[20] = {}; 149 150 snprintf(path, sizeof(path), PATH_TO_CPU "amd_pstate/status"); 151 152 if (!is_valid_path(path)) 153 return -1; 154 155 snprintf(linebuf, sizeof(linebuf), "%s\n", mode); 156 157 if (cpupower_write_sysfs(path, linebuf, 20) <= 0) 158 return -1; 159 160 return 0; 161 } 162 163 bool cpupower_amd_pstate_enabled(void) 164 { 165 char *driver = cpufreq_get_driver(0); 166 bool ret = false; 167 168 if (!driver) 169 return ret; 170 171 if (!strncmp(driver, "amd", 3)) 172 ret = true; 173 174 cpufreq_put_driver(driver); 175 176 return ret; 177 } 178 179 #endif /* #if defined(__i386__) || defined(__x86_64__) */ 180 181 int cpufreq_has_generic_boost_support(bool *active) 182 { 183 char path[SYSFS_PATH_MAX]; 184 char linebuf[2] = {}; 185 unsigned long val; 186 char *endp; 187 188 snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost"); 189 190 if (!is_valid_path(path)) 191 return -EACCES; 192 193 if (cpupower_read_sysfs(path, linebuf, 2) <= 0) 194 return -EINVAL; 195 196 val = strtoul(linebuf, &endp, 0); 197 if (endp == linebuf || errno == ERANGE) 198 return -EINVAL; 199 200 switch (val) { 201 case 0: 202 *active = false; 203 break; 204 case 1: 205 *active = true; 206 break; 207 default: 208 return -EINVAL; 209 } 210 211 return 0; 212 } 213 214 /* get_cpustate 215 * 216 * Gather the information of all online CPUs into bitmask struct 217 */ 218 void get_cpustate(void) 219 { 220 unsigned int cpu = 0; 221 222 bitmask_clearall(online_cpus); 223 bitmask_clearall(offline_cpus); 224 225 for (cpu = bitmask_first(cpus_chosen); 226 cpu <= bitmask_last(cpus_chosen); cpu++) { 227 228 if (cpupower_is_cpu_online(cpu) == 1) 229 bitmask_setbit(online_cpus, cpu); 230 else 231 bitmask_setbit(offline_cpus, cpu); 232 233 continue; 234 } 235 } 236 237 /* print_online_cpus 238 * 239 * Print the CPU numbers of all CPUs that are online currently 240 */ 241 void print_online_cpus(void) 242 { 243 int str_len = 0; 244 char *online_cpus_str = NULL; 245 246 str_len = online_cpus->size * 5; 247 online_cpus_str = (void *)malloc(sizeof(char) * str_len); 248 249 if (!bitmask_isallclear(online_cpus)) { 250 bitmask_displaylist(online_cpus_str, str_len, online_cpus); 251 printf(_("Following CPUs are online:\n%s\n"), online_cpus_str); 252 } 253 } 254 255 /* print_offline_cpus 256 * 257 * Print the CPU numbers of all CPUs that are offline currently 258 */ 259 void print_offline_cpus(void) 260 { 261 int str_len = 0; 262 char *offline_cpus_str = NULL; 263 264 str_len = offline_cpus->size * 5; 265 offline_cpus_str = (void *)malloc(sizeof(char) * str_len); 266 267 if (!bitmask_isallclear(offline_cpus)) { 268 bitmask_displaylist(offline_cpus_str, str_len, offline_cpus); 269 printf(_("Following CPUs are offline:\n%s\n"), offline_cpus_str); 270 printf(_("cpupower set operation was not performed on them\n")); 271 } 272 } 273 274 /* 275 * print_speed 276 * 277 * Print the exact CPU frequency with appropriate unit 278 */ 279 void print_speed(unsigned long speed, int no_rounding) 280 { 281 unsigned long tmp; 282 283 if (no_rounding) { 284 if (speed > 1000000) 285 printf("%u.%06u GHz", ((unsigned int)speed / 1000000), 286 ((unsigned int)speed % 1000000)); 287 else if (speed > 1000) 288 printf("%u.%03u MHz", ((unsigned int)speed / 1000), 289 (unsigned int)(speed % 1000)); 290 else 291 printf("%lu kHz", speed); 292 } else { 293 if (speed > 1000000) { 294 tmp = speed % 10000; 295 if (tmp >= 5000) 296 speed += 10000; 297 printf("%u.%02u GHz", ((unsigned int)speed / 1000000), 298 ((unsigned int)(speed % 1000000) / 10000)); 299 } else if (speed > 100000) { 300 tmp = speed % 1000; 301 if (tmp >= 500) 302 speed += 1000; 303 printf("%u MHz", ((unsigned int)speed / 1000)); 304 } else if (speed > 1000) { 305 tmp = speed % 100; 306 if (tmp >= 50) 307 speed += 100; 308 printf("%u.%01u MHz", ((unsigned int)speed / 1000), 309 ((unsigned int)(speed % 1000) / 100)); 310 } 311 } 312 } 313 314 int cpupower_set_generic_turbo_boost(int turbo_boost) 315 { 316 char path[SYSFS_PATH_MAX]; 317 char linebuf[2] = {}; 318 319 snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost"); 320 321 if (!is_valid_path(path)) 322 return -1; 323 324 snprintf(linebuf, sizeof(linebuf), "%d", turbo_boost); 325 326 if (cpupower_write_sysfs(path, linebuf, 2) <= 0) 327 return -1; 328 329 return 0; 330 } 331