xref: /linux/tools/power/cpupower/utils/helpers/misc.c (revision 26d6ed49cd008a326063d82bd731c2a82f2f4378)
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