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 bool cpupower_amd_pstate_enabled(void) 91 { 92 char *driver = cpufreq_get_driver(0); 93 bool ret = false; 94 95 if (!driver) 96 return ret; 97 98 if (!strcmp(driver, "amd-pstate")) 99 ret = true; 100 101 cpufreq_put_driver(driver); 102 103 return ret; 104 } 105 106 #endif /* #if defined(__i386__) || defined(__x86_64__) */ 107 108 /* get_cpustate 109 * 110 * Gather the information of all online CPUs into bitmask struct 111 */ 112 void get_cpustate(void) 113 { 114 unsigned int cpu = 0; 115 116 bitmask_clearall(online_cpus); 117 bitmask_clearall(offline_cpus); 118 119 for (cpu = bitmask_first(cpus_chosen); 120 cpu <= bitmask_last(cpus_chosen); cpu++) { 121 122 if (cpupower_is_cpu_online(cpu) == 1) 123 bitmask_setbit(online_cpus, cpu); 124 else 125 bitmask_setbit(offline_cpus, cpu); 126 127 continue; 128 } 129 } 130 131 /* print_online_cpus 132 * 133 * Print the CPU numbers of all CPUs that are online currently 134 */ 135 void print_online_cpus(void) 136 { 137 int str_len = 0; 138 char *online_cpus_str = NULL; 139 140 str_len = online_cpus->size * 5; 141 online_cpus_str = (void *)malloc(sizeof(char) * str_len); 142 143 if (!bitmask_isallclear(online_cpus)) { 144 bitmask_displaylist(online_cpus_str, str_len, online_cpus); 145 printf(_("Following CPUs are online:\n%s\n"), online_cpus_str); 146 } 147 } 148 149 /* print_offline_cpus 150 * 151 * Print the CPU numbers of all CPUs that are offline currently 152 */ 153 void print_offline_cpus(void) 154 { 155 int str_len = 0; 156 char *offline_cpus_str = NULL; 157 158 str_len = offline_cpus->size * 5; 159 offline_cpus_str = (void *)malloc(sizeof(char) * str_len); 160 161 if (!bitmask_isallclear(offline_cpus)) { 162 bitmask_displaylist(offline_cpus_str, str_len, offline_cpus); 163 printf(_("Following CPUs are offline:\n%s\n"), offline_cpus_str); 164 printf(_("cpupower set operation was not performed on them\n")); 165 } 166 } 167 168 /* 169 * print_speed 170 * 171 * Print the exact CPU frequency with appropriate unit 172 */ 173 void print_speed(unsigned long speed, int no_rounding) 174 { 175 unsigned long tmp; 176 177 if (no_rounding) { 178 if (speed > 1000000) 179 printf("%u.%06u GHz", ((unsigned int)speed / 1000000), 180 ((unsigned int)speed % 1000000)); 181 else if (speed > 1000) 182 printf("%u.%03u MHz", ((unsigned int)speed / 1000), 183 (unsigned int)(speed % 1000)); 184 else 185 printf("%lu kHz", speed); 186 } else { 187 if (speed > 1000000) { 188 tmp = speed % 10000; 189 if (tmp >= 5000) 190 speed += 10000; 191 printf("%u.%02u GHz", ((unsigned int)speed / 1000000), 192 ((unsigned int)(speed % 1000000) / 10000)); 193 } else if (speed > 100000) { 194 tmp = speed % 1000; 195 if (tmp >= 500) 196 speed += 1000; 197 printf("%u MHz", ((unsigned int)speed / 1000)); 198 } else if (speed > 1000) { 199 tmp = speed % 100; 200 if (tmp >= 50) 201 speed += 100; 202 printf("%u.%01u MHz", ((unsigned int)speed / 1000), 203 ((unsigned int)(speed % 1000) / 100)); 204 } 205 } 206 } 207