1b2441318SGreg Kroah-Hartman // SPDX-License-Identifier: GPL-2.0
28113ab20SBorislav Petkov 
38113ab20SBorislav Petkov #include <stdio.h>
48113ab20SBorislav Petkov #include <errno.h>
58113ab20SBorislav Petkov #include <stdlib.h>
646c273a0SHuang Rui #include <string.h>
78113ab20SBorislav Petkov 
87fe2f639SDominik Brodowski #include "helpers/helpers.h"
98113ab20SBorislav Petkov #include "helpers/sysfs.h"
1046c273a0SHuang Rui #include "cpufreq.h"
118113ab20SBorislav Petkov 
12748f0d70SBrahadambal Srinivasan #if defined(__i386__) || defined(__x86_64__)
13748f0d70SBrahadambal Srinivasan 
148113ab20SBorislav Petkov #include "cpupower_intern.h"
157fe2f639SDominik Brodowski 
16902bef73SSherry Hurwitz #define MSR_AMD_HWCR	0xc0010015
17902bef73SSherry Hurwitz 
cpufreq_has_boost_support(unsigned int cpu,int * support,int * active,int * states)182cd005caSDominik Brodowski int cpufreq_has_boost_support(unsigned int cpu, int *support, int *active,
192cd005caSDominik Brodowski 			int *states)
207fe2f639SDominik Brodowski {
217fe2f639SDominik Brodowski 	int ret;
22902bef73SSherry Hurwitz 	unsigned long long val;
237fe2f639SDominik Brodowski 
247fe2f639SDominik Brodowski 	*support = *active = *states = 0;
257fe2f639SDominik Brodowski 
267a136a8fSRobert Richter 	if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CPB) {
277fe2f639SDominik Brodowski 		*support = 1;
28902bef73SSherry Hurwitz 
29902bef73SSherry Hurwitz 		/* AMD Family 0x17 does not utilize PCI D18F4 like prior
30902bef73SSherry Hurwitz 		 * families and has no fixed discrete boost states but
31902bef73SSherry Hurwitz 		 * has Hardware determined variable increments instead.
32902bef73SSherry Hurwitz 		 */
33902bef73SSherry Hurwitz 
343a3ecfdbSNathan Fontenot 		if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_CPB_MSR) {
35902bef73SSherry Hurwitz 			if (!read_msr(cpu, MSR_AMD_HWCR, &val)) {
36902bef73SSherry Hurwitz 				if (!(val & CPUPOWER_AMD_CPBDIS))
37902bef73SSherry Hurwitz 					*active = 1;
38902bef73SSherry Hurwitz 			}
39902bef73SSherry Hurwitz 		} else {
406ae78b4eSSherry Hurwitz 			ret = amd_pci_get_num_boost_states(active, states);
416ae78b4eSSherry Hurwitz 			if (ret)
427fe2f639SDominik Brodowski 				return ret;
43902bef73SSherry Hurwitz 		}
44bf9801baSHuang Rui 	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_AMD_PSTATE) {
45bf9801baSHuang Rui 		amd_pstate_boost_init(cpu, support, active);
46029e9f73SThomas Renninger 	} else if (cpupower_cpu_info.caps & CPUPOWER_CAP_INTEL_IDA)
47029e9f73SThomas Renninger 		*support = *active = 1;
487fe2f639SDominik Brodowski 	return 0;
497fe2f639SDominik Brodowski }
508113ab20SBorislav Petkov 
cpupower_intel_get_perf_bias(unsigned int cpu)518113ab20SBorislav Petkov int cpupower_intel_get_perf_bias(unsigned int cpu)
528113ab20SBorislav Petkov {
538113ab20SBorislav Petkov 	char linebuf[MAX_LINE_LEN];
548113ab20SBorislav Petkov 	char path[SYSFS_PATH_MAX];
558113ab20SBorislav Petkov 	unsigned long val;
568113ab20SBorislav Petkov 	char *endp;
578113ab20SBorislav Petkov 
588113ab20SBorislav Petkov 	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
598113ab20SBorislav Petkov 		return -1;
608113ab20SBorislav Petkov 
618113ab20SBorislav Petkov 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu);
628113ab20SBorislav Petkov 
638113ab20SBorislav Petkov 	if (cpupower_read_sysfs(path, linebuf, MAX_LINE_LEN) == 0)
648113ab20SBorislav Petkov 		return -1;
658113ab20SBorislav Petkov 
668113ab20SBorislav Petkov 	val = strtol(linebuf, &endp, 0);
678113ab20SBorislav Petkov 	if (endp == linebuf || errno == ERANGE)
688113ab20SBorislav Petkov 		return -1;
698113ab20SBorislav Petkov 
708113ab20SBorislav Petkov 	return val;
718113ab20SBorislav Petkov }
728113ab20SBorislav Petkov 
cpupower_intel_set_perf_bias(unsigned int cpu,unsigned int val)738113ab20SBorislav Petkov int cpupower_intel_set_perf_bias(unsigned int cpu, unsigned int val)
748113ab20SBorislav Petkov {
758113ab20SBorislav Petkov 	char path[SYSFS_PATH_MAX];
768113ab20SBorislav Petkov 	char linebuf[3] = {};
778113ab20SBorislav Petkov 
788113ab20SBorislav Petkov 	if (!(cpupower_cpu_info.caps & CPUPOWER_CAP_PERF_BIAS))
798113ab20SBorislav Petkov 		return -1;
808113ab20SBorislav Petkov 
818113ab20SBorislav Petkov 	snprintf(path, sizeof(path), PATH_TO_CPU "cpu%u/power/energy_perf_bias", cpu);
828113ab20SBorislav Petkov 	snprintf(linebuf, sizeof(linebuf), "%d", val);
838113ab20SBorislav Petkov 
848113ab20SBorislav Petkov 	if (cpupower_write_sysfs(path, linebuf, 3) <= 0)
858113ab20SBorislav Petkov 		return -1;
868113ab20SBorislav Petkov 
878113ab20SBorislav Petkov 	return 0;
888113ab20SBorislav Petkov }
898113ab20SBorislav Petkov 
cpupower_set_epp(unsigned int cpu,char * epp)90f2ab5557SWyes Karny int cpupower_set_epp(unsigned int cpu, char *epp)
91f2ab5557SWyes Karny {
92f2ab5557SWyes Karny 	char path[SYSFS_PATH_MAX];
93f2ab5557SWyes Karny 	char linebuf[30] = {};
94f2ab5557SWyes Karny 
95f2ab5557SWyes Karny 	snprintf(path, sizeof(path),
96f2ab5557SWyes Karny 		PATH_TO_CPU "cpu%u/cpufreq/energy_performance_preference", cpu);
97f2ab5557SWyes Karny 
98f2ab5557SWyes Karny 	if (!is_valid_path(path))
99f2ab5557SWyes Karny 		return -1;
100f2ab5557SWyes Karny 
101f2ab5557SWyes Karny 	snprintf(linebuf, sizeof(linebuf), "%s", epp);
102f2ab5557SWyes Karny 
103f2ab5557SWyes Karny 	if (cpupower_write_sysfs(path, linebuf, 30) <= 0)
104f2ab5557SWyes Karny 		return -1;
105f2ab5557SWyes Karny 
106f2ab5557SWyes Karny 	return 0;
107f2ab5557SWyes Karny }
108f2ab5557SWyes Karny 
cpupower_set_amd_pstate_mode(char * mode)109df8776b0SWyes Karny int cpupower_set_amd_pstate_mode(char *mode)
110df8776b0SWyes Karny {
111df8776b0SWyes Karny 	char path[SYSFS_PATH_MAX];
112df8776b0SWyes Karny 	char linebuf[20] = {};
113df8776b0SWyes Karny 
114df8776b0SWyes Karny 	snprintf(path, sizeof(path), PATH_TO_CPU "amd_pstate/status");
115df8776b0SWyes Karny 
116df8776b0SWyes Karny 	if (!is_valid_path(path))
117df8776b0SWyes Karny 		return -1;
118df8776b0SWyes Karny 
119df8776b0SWyes Karny 	snprintf(linebuf, sizeof(linebuf), "%s\n", mode);
120df8776b0SWyes Karny 
121df8776b0SWyes Karny 	if (cpupower_write_sysfs(path, linebuf, 20) <= 0)
122df8776b0SWyes Karny 		return -1;
123df8776b0SWyes Karny 
124df8776b0SWyes Karny 	return 0;
125df8776b0SWyes Karny }
126df8776b0SWyes Karny 
cpupower_set_turbo_boost(int turbo_boost)127*eb426fc6SWyes Karny int cpupower_set_turbo_boost(int turbo_boost)
128*eb426fc6SWyes Karny {
129*eb426fc6SWyes Karny 	char path[SYSFS_PATH_MAX];
130*eb426fc6SWyes Karny 	char linebuf[2] = {};
131*eb426fc6SWyes Karny 
132*eb426fc6SWyes Karny 	snprintf(path, sizeof(path), PATH_TO_CPU "cpufreq/boost");
133*eb426fc6SWyes Karny 
134*eb426fc6SWyes Karny 	if (!is_valid_path(path))
135*eb426fc6SWyes Karny 		return -1;
136*eb426fc6SWyes Karny 
137*eb426fc6SWyes Karny 	snprintf(linebuf, sizeof(linebuf), "%d", turbo_boost);
138*eb426fc6SWyes Karny 
139*eb426fc6SWyes Karny 	if (cpupower_write_sysfs(path, linebuf, 2) <= 0)
140*eb426fc6SWyes Karny 		return -1;
141*eb426fc6SWyes Karny 
142*eb426fc6SWyes Karny 	return 0;
143*eb426fc6SWyes Karny }
144*eb426fc6SWyes Karny 
cpupower_amd_pstate_enabled(void)14546c273a0SHuang Rui bool cpupower_amd_pstate_enabled(void)
14646c273a0SHuang Rui {
14746c273a0SHuang Rui 	char *driver = cpufreq_get_driver(0);
14846c273a0SHuang Rui 	bool ret = false;
14946c273a0SHuang Rui 
15046c273a0SHuang Rui 	if (!driver)
15146c273a0SHuang Rui 		return ret;
15246c273a0SHuang Rui 
153a1cf97c2SWyes Karny 	if (!strncmp(driver, "amd", 3))
15446c273a0SHuang Rui 		ret = true;
15546c273a0SHuang Rui 
15646c273a0SHuang Rui 	cpufreq_put_driver(driver);
15746c273a0SHuang Rui 
15846c273a0SHuang Rui 	return ret;
15946c273a0SHuang Rui }
16046c273a0SHuang Rui 
1617fe2f639SDominik Brodowski #endif /* #if defined(__i386__) || defined(__x86_64__) */
162748f0d70SBrahadambal Srinivasan 
163748f0d70SBrahadambal Srinivasan /* get_cpustate
164748f0d70SBrahadambal Srinivasan  *
165748f0d70SBrahadambal Srinivasan  * Gather the information of all online CPUs into bitmask struct
166748f0d70SBrahadambal Srinivasan  */
get_cpustate(void)167748f0d70SBrahadambal Srinivasan void get_cpustate(void)
168748f0d70SBrahadambal Srinivasan {
169748f0d70SBrahadambal Srinivasan 	unsigned int cpu = 0;
170748f0d70SBrahadambal Srinivasan 
171748f0d70SBrahadambal Srinivasan 	bitmask_clearall(online_cpus);
172748f0d70SBrahadambal Srinivasan 	bitmask_clearall(offline_cpus);
173748f0d70SBrahadambal Srinivasan 
174748f0d70SBrahadambal Srinivasan 	for (cpu = bitmask_first(cpus_chosen);
175748f0d70SBrahadambal Srinivasan 		cpu <= bitmask_last(cpus_chosen); cpu++) {
176748f0d70SBrahadambal Srinivasan 
177748f0d70SBrahadambal Srinivasan 		if (cpupower_is_cpu_online(cpu) == 1)
178748f0d70SBrahadambal Srinivasan 			bitmask_setbit(online_cpus, cpu);
179748f0d70SBrahadambal Srinivasan 		else
180748f0d70SBrahadambal Srinivasan 			bitmask_setbit(offline_cpus, cpu);
181748f0d70SBrahadambal Srinivasan 
182748f0d70SBrahadambal Srinivasan 		continue;
183748f0d70SBrahadambal Srinivasan 	}
184748f0d70SBrahadambal Srinivasan }
185748f0d70SBrahadambal Srinivasan 
186748f0d70SBrahadambal Srinivasan /* print_online_cpus
187748f0d70SBrahadambal Srinivasan  *
188748f0d70SBrahadambal Srinivasan  * Print the CPU numbers of all CPUs that are online currently
189748f0d70SBrahadambal Srinivasan  */
print_online_cpus(void)190748f0d70SBrahadambal Srinivasan void print_online_cpus(void)
191748f0d70SBrahadambal Srinivasan {
192748f0d70SBrahadambal Srinivasan 	int str_len = 0;
193748f0d70SBrahadambal Srinivasan 	char *online_cpus_str = NULL;
194748f0d70SBrahadambal Srinivasan 
195748f0d70SBrahadambal Srinivasan 	str_len = online_cpus->size * 5;
196748f0d70SBrahadambal Srinivasan 	online_cpus_str = (void *)malloc(sizeof(char) * str_len);
197748f0d70SBrahadambal Srinivasan 
198748f0d70SBrahadambal Srinivasan 	if (!bitmask_isallclear(online_cpus)) {
199748f0d70SBrahadambal Srinivasan 		bitmask_displaylist(online_cpus_str, str_len, online_cpus);
200748f0d70SBrahadambal Srinivasan 		printf(_("Following CPUs are online:\n%s\n"), online_cpus_str);
201748f0d70SBrahadambal Srinivasan 	}
202748f0d70SBrahadambal Srinivasan }
203748f0d70SBrahadambal Srinivasan 
204748f0d70SBrahadambal Srinivasan /* print_offline_cpus
205748f0d70SBrahadambal Srinivasan  *
206748f0d70SBrahadambal Srinivasan  * Print the CPU numbers of all CPUs that are offline currently
207748f0d70SBrahadambal Srinivasan  */
print_offline_cpus(void)208748f0d70SBrahadambal Srinivasan void print_offline_cpus(void)
209748f0d70SBrahadambal Srinivasan {
210748f0d70SBrahadambal Srinivasan 	int str_len = 0;
211748f0d70SBrahadambal Srinivasan 	char *offline_cpus_str = NULL;
212748f0d70SBrahadambal Srinivasan 
213748f0d70SBrahadambal Srinivasan 	str_len = offline_cpus->size * 5;
214748f0d70SBrahadambal Srinivasan 	offline_cpus_str = (void *)malloc(sizeof(char) * str_len);
215748f0d70SBrahadambal Srinivasan 
216748f0d70SBrahadambal Srinivasan 	if (!bitmask_isallclear(offline_cpus)) {
217748f0d70SBrahadambal Srinivasan 		bitmask_displaylist(offline_cpus_str, str_len, offline_cpus);
218748f0d70SBrahadambal Srinivasan 		printf(_("Following CPUs are offline:\n%s\n"), offline_cpus_str);
219748f0d70SBrahadambal Srinivasan 		printf(_("cpupower set operation was not performed on them\n"));
220748f0d70SBrahadambal Srinivasan 	}
221748f0d70SBrahadambal Srinivasan }
22235fdf42dSHuang Rui 
22335fdf42dSHuang Rui /*
22435fdf42dSHuang Rui  * print_speed
22535fdf42dSHuang Rui  *
22635fdf42dSHuang Rui  * Print the exact CPU frequency with appropriate unit
22735fdf42dSHuang Rui  */
print_speed(unsigned long speed,int no_rounding)22835fdf42dSHuang Rui void print_speed(unsigned long speed, int no_rounding)
22935fdf42dSHuang Rui {
23035fdf42dSHuang Rui 	unsigned long tmp;
23135fdf42dSHuang Rui 
23235fdf42dSHuang Rui 	if (no_rounding) {
23335fdf42dSHuang Rui 		if (speed > 1000000)
23435fdf42dSHuang Rui 			printf("%u.%06u GHz", ((unsigned int)speed / 1000000),
23535fdf42dSHuang Rui 			       ((unsigned int)speed % 1000000));
23635fdf42dSHuang Rui 		else if (speed > 1000)
23735fdf42dSHuang Rui 			printf("%u.%03u MHz", ((unsigned int)speed / 1000),
23835fdf42dSHuang Rui 			       (unsigned int)(speed % 1000));
23935fdf42dSHuang Rui 		else
24035fdf42dSHuang Rui 			printf("%lu kHz", speed);
24135fdf42dSHuang Rui 	} else {
24235fdf42dSHuang Rui 		if (speed > 1000000) {
24335fdf42dSHuang Rui 			tmp = speed % 10000;
24435fdf42dSHuang Rui 			if (tmp >= 5000)
24535fdf42dSHuang Rui 				speed += 10000;
24635fdf42dSHuang Rui 			printf("%u.%02u GHz", ((unsigned int)speed / 1000000),
24735fdf42dSHuang Rui 			       ((unsigned int)(speed % 1000000) / 10000));
24835fdf42dSHuang Rui 		} else if (speed > 100000) {
24935fdf42dSHuang Rui 			tmp = speed % 1000;
25035fdf42dSHuang Rui 			if (tmp >= 500)
25135fdf42dSHuang Rui 				speed += 1000;
25235fdf42dSHuang Rui 			printf("%u MHz", ((unsigned int)speed / 1000));
25335fdf42dSHuang Rui 		} else if (speed > 1000) {
25435fdf42dSHuang Rui 			tmp = speed % 100;
25535fdf42dSHuang Rui 			if (tmp >= 50)
25635fdf42dSHuang Rui 				speed += 100;
25735fdf42dSHuang Rui 			printf("%u.%01u MHz", ((unsigned int)speed / 1000),
25835fdf42dSHuang Rui 			       ((unsigned int)(speed % 1000) / 100));
25935fdf42dSHuang Rui 		}
26035fdf42dSHuang Rui 	}
26135fdf42dSHuang Rui }
262