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