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