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
cpufreq_has_x86_boost_support(unsigned int cpu,int * support,int * active,int * states)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
cpupower_intel_get_perf_bias(unsigned int cpu)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
cpupower_intel_set_perf_bias(unsigned int cpu,unsigned int val)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
cpupower_set_epp(unsigned int cpu,char * epp)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
cpupower_set_amd_pstate_mode(char * mode)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
cpupower_amd_pstate_enabled(void)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
cpufreq_has_generic_boost_support(bool * active)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 */
get_cpustate(void)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 */
print_online_cpus(void)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 */
print_offline_cpus(void)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 */
print_speed(unsigned long speed,int no_rounding)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
cpupower_set_turbo_boost(int turbo_boost)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