xref: /dpdk/drivers/power/intel_pstate/intel_pstate_cpufreq.c (revision 6f987b594fa6751b49769755fe1d1bf9f9d15ac4)
1*6f987b59SSivaprasad Tummala /* SPDX-License-Identifier: BSD-3-Clause
2*6f987b59SSivaprasad Tummala  * Copyright(c) 2018 Intel Corporation
3*6f987b59SSivaprasad Tummala  */
4*6f987b59SSivaprasad Tummala 
5*6f987b59SSivaprasad Tummala #include <stdio.h>
6*6f987b59SSivaprasad Tummala #include <stdlib.h>
7*6f987b59SSivaprasad Tummala #include <fcntl.h>
8*6f987b59SSivaprasad Tummala #include <string.h>
9*6f987b59SSivaprasad Tummala #include <unistd.h>
10*6f987b59SSivaprasad Tummala #include <limits.h>
11*6f987b59SSivaprasad Tummala #include <errno.h>
12*6f987b59SSivaprasad Tummala #include <inttypes.h>
13*6f987b59SSivaprasad Tummala 
14*6f987b59SSivaprasad Tummala #include <rte_memcpy.h>
15*6f987b59SSivaprasad Tummala #include <rte_stdatomic.h>
16*6f987b59SSivaprasad Tummala 
17*6f987b59SSivaprasad Tummala #include "rte_power_pmd_mgmt.h"
18*6f987b59SSivaprasad Tummala #include "intel_pstate_cpufreq.h"
19*6f987b59SSivaprasad Tummala #include "power_common.h"
20*6f987b59SSivaprasad Tummala 
21*6f987b59SSivaprasad Tummala /* macros used for rounding frequency to nearest 100000 */
22*6f987b59SSivaprasad Tummala #define FREQ_ROUNDING_DELTA 50000
23*6f987b59SSivaprasad Tummala #define ROUND_FREQ_TO_N_100000 100000
24*6f987b59SSivaprasad Tummala 
25*6f987b59SSivaprasad Tummala #define BUS_FREQ     100000
26*6f987b59SSivaprasad Tummala 
27*6f987b59SSivaprasad Tummala #define POWER_GOVERNOR_PERF "performance"
28*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_MAX_FREQ \
29*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_max_freq"
30*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_MIN_FREQ  \
31*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_min_freq"
32*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_CUR_FREQ  \
33*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq"
34*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_BASE_MAX_FREQ \
35*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq"
36*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_BASE_MIN_FREQ  \
37*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_min_freq"
38*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_BASE_FREQ  \
39*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/cpu%u/cpufreq/base_frequency"
40*6f987b59SSivaprasad Tummala #define POWER_SYSFILE_TURBO_PCT  \
41*6f987b59SSivaprasad Tummala 		"/sys/devices/system/cpu/intel_pstate/turbo_pct"
42*6f987b59SSivaprasad Tummala #define POWER_PSTATE_DRIVER "intel_pstate"
43*6f987b59SSivaprasad Tummala 
44*6f987b59SSivaprasad Tummala 
45*6f987b59SSivaprasad Tummala enum power_state {
46*6f987b59SSivaprasad Tummala 	POWER_IDLE = 0,
47*6f987b59SSivaprasad Tummala 	POWER_ONGOING,
48*6f987b59SSivaprasad Tummala 	POWER_USED,
49*6f987b59SSivaprasad Tummala 	POWER_UNKNOWN
50*6f987b59SSivaprasad Tummala };
51*6f987b59SSivaprasad Tummala 
52*6f987b59SSivaprasad Tummala struct __rte_cache_aligned pstate_power_info {
53*6f987b59SSivaprasad Tummala 	unsigned int lcore_id;               /**< Logical core id */
54*6f987b59SSivaprasad Tummala 	uint32_t freqs[RTE_MAX_LCORE_FREQS]; /**< Frequency array */
55*6f987b59SSivaprasad Tummala 	uint32_t nb_freqs;                   /**< number of available freqs */
56*6f987b59SSivaprasad Tummala 	FILE *f_cur_min;                     /**< FD of scaling_min */
57*6f987b59SSivaprasad Tummala 	FILE *f_cur_max;                     /**< FD of scaling_max */
58*6f987b59SSivaprasad Tummala 	char governor_ori[32];               /**< Original governor name */
59*6f987b59SSivaprasad Tummala 	uint32_t curr_idx;                   /**< Freq index in freqs array */
60*6f987b59SSivaprasad Tummala 	uint32_t non_turbo_max_ratio;        /**< Non Turbo Max ratio  */
61*6f987b59SSivaprasad Tummala 	uint32_t sys_max_freq;               /**< system wide max freq  */
62*6f987b59SSivaprasad Tummala 	uint32_t core_base_freq;             /**< core base freq  */
63*6f987b59SSivaprasad Tummala 	RTE_ATOMIC(uint32_t) state;          /**< Power in use state */
64*6f987b59SSivaprasad Tummala 	uint16_t turbo_available;            /**< Turbo Boost available */
65*6f987b59SSivaprasad Tummala 	uint16_t turbo_enable;               /**< Turbo Boost enable/disable */
66*6f987b59SSivaprasad Tummala 	uint16_t priority_core;              /**< High Performance core */
67*6f987b59SSivaprasad Tummala };
68*6f987b59SSivaprasad Tummala 
69*6f987b59SSivaprasad Tummala 
70*6f987b59SSivaprasad Tummala static struct pstate_power_info lcore_power_info[RTE_MAX_LCORE];
71*6f987b59SSivaprasad Tummala 
72*6f987b59SSivaprasad Tummala /**
73*6f987b59SSivaprasad Tummala  * It is to read the turbo mode percentage from sysfs
74*6f987b59SSivaprasad Tummala  */
75*6f987b59SSivaprasad Tummala static int32_t
76*6f987b59SSivaprasad Tummala power_read_turbo_pct(uint64_t *outVal)
77*6f987b59SSivaprasad Tummala {
78*6f987b59SSivaprasad Tummala 	int fd, ret;
79*6f987b59SSivaprasad Tummala 	char val[4] = {0};
80*6f987b59SSivaprasad Tummala 	char *endptr;
81*6f987b59SSivaprasad Tummala 
82*6f987b59SSivaprasad Tummala 	fd = open(POWER_SYSFILE_TURBO_PCT, O_RDONLY);
83*6f987b59SSivaprasad Tummala 
84*6f987b59SSivaprasad Tummala 	if (fd < 0) {
85*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Error opening '%s': %s", POWER_SYSFILE_TURBO_PCT,
86*6f987b59SSivaprasad Tummala 				 strerror(errno));
87*6f987b59SSivaprasad Tummala 		return fd;
88*6f987b59SSivaprasad Tummala 	}
89*6f987b59SSivaprasad Tummala 
90*6f987b59SSivaprasad Tummala 	ret = read(fd, val, sizeof(val));
91*6f987b59SSivaprasad Tummala 
92*6f987b59SSivaprasad Tummala 	if (ret < 0) {
93*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Error reading '%s': %s", POWER_SYSFILE_TURBO_PCT,
94*6f987b59SSivaprasad Tummala 				 strerror(errno));
95*6f987b59SSivaprasad Tummala 		goto out;
96*6f987b59SSivaprasad Tummala 	}
97*6f987b59SSivaprasad Tummala 
98*6f987b59SSivaprasad Tummala 	errno = 0;
99*6f987b59SSivaprasad Tummala 	*outVal = (uint64_t) strtol(val, &endptr, 10);
100*6f987b59SSivaprasad Tummala 	if (errno != 0 || (*endptr != 0 && *endptr != '\n')) {
101*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Error converting str to digits, read from %s: %s",
102*6f987b59SSivaprasad Tummala 				 POWER_SYSFILE_TURBO_PCT, strerror(errno));
103*6f987b59SSivaprasad Tummala 		ret = -1;
104*6f987b59SSivaprasad Tummala 		goto out;
105*6f987b59SSivaprasad Tummala 	}
106*6f987b59SSivaprasad Tummala 
107*6f987b59SSivaprasad Tummala 	POWER_DEBUG_LOG("power turbo pct: %"PRIu64, *outVal);
108*6f987b59SSivaprasad Tummala 
109*6f987b59SSivaprasad Tummala out:	close(fd);
110*6f987b59SSivaprasad Tummala 	return ret;
111*6f987b59SSivaprasad Tummala }
112*6f987b59SSivaprasad Tummala 
113*6f987b59SSivaprasad Tummala /**
114*6f987b59SSivaprasad Tummala  * It is to fopen the sys file for the future setting the lcore frequency.
115*6f987b59SSivaprasad Tummala  */
116*6f987b59SSivaprasad Tummala static int
117*6f987b59SSivaprasad Tummala power_init_for_setting_freq(struct pstate_power_info *pi)
118*6f987b59SSivaprasad Tummala {
119*6f987b59SSivaprasad Tummala 	FILE *f_base = NULL, *f_base_min = NULL, *f_base_max = NULL,
120*6f987b59SSivaprasad Tummala 	     *f_min = NULL, *f_max = NULL;
121*6f987b59SSivaprasad Tummala 	uint32_t base_ratio, base_min_ratio, base_max_ratio;
122*6f987b59SSivaprasad Tummala 	uint64_t max_non_turbo;
123*6f987b59SSivaprasad Tummala 	int ret;
124*6f987b59SSivaprasad Tummala 
125*6f987b59SSivaprasad Tummala 	/* open all files we expect to have open */
126*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_base_max, "r", POWER_SYSFILE_BASE_MAX_FREQ,
127*6f987b59SSivaprasad Tummala 			pi->lcore_id);
128*6f987b59SSivaprasad Tummala 	if (f_base_max == NULL) {
129*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
130*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MAX_FREQ);
131*6f987b59SSivaprasad Tummala 		goto err;
132*6f987b59SSivaprasad Tummala 	}
133*6f987b59SSivaprasad Tummala 
134*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_base_min, "r", POWER_SYSFILE_BASE_MIN_FREQ,
135*6f987b59SSivaprasad Tummala 			pi->lcore_id);
136*6f987b59SSivaprasad Tummala 	if (f_base_min == NULL) {
137*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
138*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MIN_FREQ);
139*6f987b59SSivaprasad Tummala 		goto err;
140*6f987b59SSivaprasad Tummala 	}
141*6f987b59SSivaprasad Tummala 
142*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_min, "rw+", POWER_SYSFILE_MIN_FREQ,
143*6f987b59SSivaprasad Tummala 			pi->lcore_id);
144*6f987b59SSivaprasad Tummala 	if (f_min == NULL) {
145*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
146*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_MIN_FREQ);
147*6f987b59SSivaprasad Tummala 		goto err;
148*6f987b59SSivaprasad Tummala 	}
149*6f987b59SSivaprasad Tummala 
150*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_max, "rw+", POWER_SYSFILE_MAX_FREQ,
151*6f987b59SSivaprasad Tummala 			pi->lcore_id);
152*6f987b59SSivaprasad Tummala 	if (f_max == NULL) {
153*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
154*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_MAX_FREQ);
155*6f987b59SSivaprasad Tummala 		goto err;
156*6f987b59SSivaprasad Tummala 	}
157*6f987b59SSivaprasad Tummala 
158*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_base, "r", POWER_SYSFILE_BASE_FREQ,
159*6f987b59SSivaprasad Tummala 			pi->lcore_id);
160*6f987b59SSivaprasad Tummala 	/* base ratio file may not exist in some kernels, so no error check */
161*6f987b59SSivaprasad Tummala 
162*6f987b59SSivaprasad Tummala 	/* read base max ratio */
163*6f987b59SSivaprasad Tummala 	ret = read_core_sysfs_u32(f_base_max, &base_max_ratio);
164*6f987b59SSivaprasad Tummala 	if (ret < 0) {
165*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Failed to read %s",
166*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MAX_FREQ);
167*6f987b59SSivaprasad Tummala 		goto err;
168*6f987b59SSivaprasad Tummala 	}
169*6f987b59SSivaprasad Tummala 
170*6f987b59SSivaprasad Tummala 	/* read base min ratio */
171*6f987b59SSivaprasad Tummala 	ret = read_core_sysfs_u32(f_base_min, &base_min_ratio);
172*6f987b59SSivaprasad Tummala 	if (ret < 0) {
173*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Failed to read %s",
174*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MIN_FREQ);
175*6f987b59SSivaprasad Tummala 		goto err;
176*6f987b59SSivaprasad Tummala 	}
177*6f987b59SSivaprasad Tummala 
178*6f987b59SSivaprasad Tummala 	/* base ratio may not exist */
179*6f987b59SSivaprasad Tummala 	if (f_base != NULL) {
180*6f987b59SSivaprasad Tummala 		ret = read_core_sysfs_u32(f_base, &base_ratio);
181*6f987b59SSivaprasad Tummala 		if (ret < 0) {
182*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Failed to read %s",
183*6f987b59SSivaprasad Tummala 					POWER_SYSFILE_BASE_FREQ);
184*6f987b59SSivaprasad Tummala 			goto err;
185*6f987b59SSivaprasad Tummala 		}
186*6f987b59SSivaprasad Tummala 	} else {
187*6f987b59SSivaprasad Tummala 		base_ratio = 0;
188*6f987b59SSivaprasad Tummala 	}
189*6f987b59SSivaprasad Tummala 
190*6f987b59SSivaprasad Tummala 	/* convert ratios to bins */
191*6f987b59SSivaprasad Tummala 	base_max_ratio /= BUS_FREQ;
192*6f987b59SSivaprasad Tummala 	base_min_ratio /= BUS_FREQ;
193*6f987b59SSivaprasad Tummala 	base_ratio /= BUS_FREQ;
194*6f987b59SSivaprasad Tummala 
195*6f987b59SSivaprasad Tummala 	/* assign file handles */
196*6f987b59SSivaprasad Tummala 	pi->f_cur_min = f_min;
197*6f987b59SSivaprasad Tummala 	pi->f_cur_max = f_max;
198*6f987b59SSivaprasad Tummala 
199*6f987b59SSivaprasad Tummala 	/* try to get turbo from global sysfs entry for less privileges than from MSR */
200*6f987b59SSivaprasad Tummala 	if (power_read_turbo_pct(&max_non_turbo) < 0)
201*6f987b59SSivaprasad Tummala 		goto err;
202*6f987b59SSivaprasad Tummala 	/* no errors after this point */
203*6f987b59SSivaprasad Tummala 
204*6f987b59SSivaprasad Tummala 	max_non_turbo = base_min_ratio
205*6f987b59SSivaprasad Tummala 		      + (100 - max_non_turbo) * (base_max_ratio - base_min_ratio) / 100;
206*6f987b59SSivaprasad Tummala 
207*6f987b59SSivaprasad Tummala 	POWER_DEBUG_LOG("no turbo perf %"PRIu64, max_non_turbo);
208*6f987b59SSivaprasad Tummala 
209*6f987b59SSivaprasad Tummala 	pi->non_turbo_max_ratio = (uint32_t)max_non_turbo;
210*6f987b59SSivaprasad Tummala 
211*6f987b59SSivaprasad Tummala 	/*
212*6f987b59SSivaprasad Tummala 	 * If base_frequency is reported as greater than the maximum
213*6f987b59SSivaprasad Tummala 	 * turbo frequency, that's a known issue with some kernels.
214*6f987b59SSivaprasad Tummala 	 * Set base_frequency to max_non_turbo as a workaround.
215*6f987b59SSivaprasad Tummala 	 */
216*6f987b59SSivaprasad Tummala 	if (base_ratio > base_max_ratio) {
217*6f987b59SSivaprasad Tummala 		/* base_ratio is greater than max turbo. Kernel bug. */
218*6f987b59SSivaprasad Tummala 		pi->priority_core = 0;
219*6f987b59SSivaprasad Tummala 		goto out;
220*6f987b59SSivaprasad Tummala 	}
221*6f987b59SSivaprasad Tummala 
222*6f987b59SSivaprasad Tummala 	/*
223*6f987b59SSivaprasad Tummala 	 * If base_frequency is reported as greater than the maximum
224*6f987b59SSivaprasad Tummala 	 * non-turbo frequency, then mark it as a high priority core.
225*6f987b59SSivaprasad Tummala 	 */
226*6f987b59SSivaprasad Tummala 	if (base_ratio > max_non_turbo)
227*6f987b59SSivaprasad Tummala 		pi->priority_core = 1;
228*6f987b59SSivaprasad Tummala 	else
229*6f987b59SSivaprasad Tummala 		pi->priority_core = 0;
230*6f987b59SSivaprasad Tummala 	pi->core_base_freq = base_ratio * BUS_FREQ;
231*6f987b59SSivaprasad Tummala 
232*6f987b59SSivaprasad Tummala out:
233*6f987b59SSivaprasad Tummala 	if (f_base != NULL)
234*6f987b59SSivaprasad Tummala 		fclose(f_base);
235*6f987b59SSivaprasad Tummala 	fclose(f_base_max);
236*6f987b59SSivaprasad Tummala 	fclose(f_base_min);
237*6f987b59SSivaprasad Tummala 	/* f_min and f_max are stored, no need to close */
238*6f987b59SSivaprasad Tummala 	return 0;
239*6f987b59SSivaprasad Tummala 
240*6f987b59SSivaprasad Tummala err:
241*6f987b59SSivaprasad Tummala 	if (f_base != NULL)
242*6f987b59SSivaprasad Tummala 		fclose(f_base);
243*6f987b59SSivaprasad Tummala 	if (f_base_min != NULL)
244*6f987b59SSivaprasad Tummala 		fclose(f_base_min);
245*6f987b59SSivaprasad Tummala 	if (f_base_max != NULL)
246*6f987b59SSivaprasad Tummala 		fclose(f_base_max);
247*6f987b59SSivaprasad Tummala 	if (f_min != NULL)
248*6f987b59SSivaprasad Tummala 		fclose(f_min);
249*6f987b59SSivaprasad Tummala 	if (f_max != NULL)
250*6f987b59SSivaprasad Tummala 		fclose(f_max);
251*6f987b59SSivaprasad Tummala 	return -1;
252*6f987b59SSivaprasad Tummala }
253*6f987b59SSivaprasad Tummala 
254*6f987b59SSivaprasad Tummala static int
255*6f987b59SSivaprasad Tummala set_freq_internal(struct pstate_power_info *pi, uint32_t idx)
256*6f987b59SSivaprasad Tummala {
257*6f987b59SSivaprasad Tummala 	uint32_t target_freq = 0;
258*6f987b59SSivaprasad Tummala 
259*6f987b59SSivaprasad Tummala 	if (idx >= RTE_MAX_LCORE_FREQS || idx >= pi->nb_freqs) {
260*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid frequency index %u, which "
261*6f987b59SSivaprasad Tummala 				"should be less than %u", idx, pi->nb_freqs);
262*6f987b59SSivaprasad Tummala 		return -1;
263*6f987b59SSivaprasad Tummala 	}
264*6f987b59SSivaprasad Tummala 
265*6f987b59SSivaprasad Tummala 	/* Check if it is the same as current */
266*6f987b59SSivaprasad Tummala 	if (idx == pi->curr_idx)
267*6f987b59SSivaprasad Tummala 		return 0;
268*6f987b59SSivaprasad Tummala 
269*6f987b59SSivaprasad Tummala 	/* Because Intel Pstate Driver only allow user change min/max hint
270*6f987b59SSivaprasad Tummala 	 * User need change the min/max as same value.
271*6f987b59SSivaprasad Tummala 	 */
272*6f987b59SSivaprasad Tummala 	if (fseek(pi->f_cur_min, 0, SEEK_SET) < 0) {
273*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Fail to set file position indicator to 0 "
274*6f987b59SSivaprasad Tummala 				"for setting frequency for lcore %u",
275*6f987b59SSivaprasad Tummala 				pi->lcore_id);
276*6f987b59SSivaprasad Tummala 		return -1;
277*6f987b59SSivaprasad Tummala 	}
278*6f987b59SSivaprasad Tummala 
279*6f987b59SSivaprasad Tummala 	if (fseek(pi->f_cur_max, 0, SEEK_SET) < 0) {
280*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Fail to set file position indicator to 0 "
281*6f987b59SSivaprasad Tummala 				"for setting frequency for lcore %u",
282*6f987b59SSivaprasad Tummala 				pi->lcore_id);
283*6f987b59SSivaprasad Tummala 		return -1;
284*6f987b59SSivaprasad Tummala 	}
285*6f987b59SSivaprasad Tummala 
286*6f987b59SSivaprasad Tummala 	/* Turbo is available and enabled, first freq bucket is sys max freq */
287*6f987b59SSivaprasad Tummala 	if (pi->turbo_available && idx == 0) {
288*6f987b59SSivaprasad Tummala 		if (pi->turbo_enable)
289*6f987b59SSivaprasad Tummala 			target_freq = pi->sys_max_freq;
290*6f987b59SSivaprasad Tummala 		else {
291*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Turbo is off, frequency can't be scaled up more %u",
292*6f987b59SSivaprasad Tummala 					pi->lcore_id);
293*6f987b59SSivaprasad Tummala 			return -1;
294*6f987b59SSivaprasad Tummala 		}
295*6f987b59SSivaprasad Tummala 	} else
296*6f987b59SSivaprasad Tummala 		target_freq = pi->freqs[idx];
297*6f987b59SSivaprasad Tummala 
298*6f987b59SSivaprasad Tummala 	/* Decrease freq, the min freq should be updated first */
299*6f987b59SSivaprasad Tummala 	if (idx  >  pi->curr_idx) {
300*6f987b59SSivaprasad Tummala 
301*6f987b59SSivaprasad Tummala 		if (fprintf(pi->f_cur_min, "%u", target_freq) < 0) {
302*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Fail to write new frequency for "
303*6f987b59SSivaprasad Tummala 					"lcore %u", pi->lcore_id);
304*6f987b59SSivaprasad Tummala 			return -1;
305*6f987b59SSivaprasad Tummala 		}
306*6f987b59SSivaprasad Tummala 
307*6f987b59SSivaprasad Tummala 		if (fprintf(pi->f_cur_max, "%u", target_freq) < 0) {
308*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Fail to write new frequency for "
309*6f987b59SSivaprasad Tummala 					"lcore %u", pi->lcore_id);
310*6f987b59SSivaprasad Tummala 			return -1;
311*6f987b59SSivaprasad Tummala 		}
312*6f987b59SSivaprasad Tummala 
313*6f987b59SSivaprasad Tummala 		POWER_DEBUG_LOG("Frequency '%u' to be set for lcore %u",
314*6f987b59SSivaprasad Tummala 				  target_freq, pi->lcore_id);
315*6f987b59SSivaprasad Tummala 
316*6f987b59SSivaprasad Tummala 		fflush(pi->f_cur_min);
317*6f987b59SSivaprasad Tummala 		fflush(pi->f_cur_max);
318*6f987b59SSivaprasad Tummala 
319*6f987b59SSivaprasad Tummala 	}
320*6f987b59SSivaprasad Tummala 
321*6f987b59SSivaprasad Tummala 	/* Increase freq, the max freq should be updated first */
322*6f987b59SSivaprasad Tummala 	if (idx  <  pi->curr_idx) {
323*6f987b59SSivaprasad Tummala 
324*6f987b59SSivaprasad Tummala 		if (fprintf(pi->f_cur_max, "%u", target_freq) < 0) {
325*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Fail to write new frequency for "
326*6f987b59SSivaprasad Tummala 					"lcore %u", pi->lcore_id);
327*6f987b59SSivaprasad Tummala 			return -1;
328*6f987b59SSivaprasad Tummala 		}
329*6f987b59SSivaprasad Tummala 
330*6f987b59SSivaprasad Tummala 		if (fprintf(pi->f_cur_min, "%u", target_freq) < 0) {
331*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR, "Fail to write new frequency for "
332*6f987b59SSivaprasad Tummala 					"lcore %u", pi->lcore_id);
333*6f987b59SSivaprasad Tummala 			return -1;
334*6f987b59SSivaprasad Tummala 		}
335*6f987b59SSivaprasad Tummala 
336*6f987b59SSivaprasad Tummala 		POWER_DEBUG_LOG("Frequency '%u' to be set for lcore %u",
337*6f987b59SSivaprasad Tummala 				  target_freq, pi->lcore_id);
338*6f987b59SSivaprasad Tummala 
339*6f987b59SSivaprasad Tummala 		fflush(pi->f_cur_max);
340*6f987b59SSivaprasad Tummala 		fflush(pi->f_cur_min);
341*6f987b59SSivaprasad Tummala 	}
342*6f987b59SSivaprasad Tummala 
343*6f987b59SSivaprasad Tummala 	pi->curr_idx = idx;
344*6f987b59SSivaprasad Tummala 
345*6f987b59SSivaprasad Tummala 	return 1;
346*6f987b59SSivaprasad Tummala }
347*6f987b59SSivaprasad Tummala 
348*6f987b59SSivaprasad Tummala /**
349*6f987b59SSivaprasad Tummala  * It is to check the current scaling governor by reading sys file, and then
350*6f987b59SSivaprasad Tummala  * set it into 'performance' if it is not by writing the sys file. The original
351*6f987b59SSivaprasad Tummala  * governor will be saved for rolling back.
352*6f987b59SSivaprasad Tummala  */
353*6f987b59SSivaprasad Tummala static int
354*6f987b59SSivaprasad Tummala power_set_governor_performance(struct pstate_power_info *pi)
355*6f987b59SSivaprasad Tummala {
356*6f987b59SSivaprasad Tummala 	return power_set_governor(pi->lcore_id, POWER_GOVERNOR_PERF,
357*6f987b59SSivaprasad Tummala 			pi->governor_ori, sizeof(pi->governor_ori));
358*6f987b59SSivaprasad Tummala }
359*6f987b59SSivaprasad Tummala 
360*6f987b59SSivaprasad Tummala /**
361*6f987b59SSivaprasad Tummala  * It is to check the governor and then set the original governor back if
362*6f987b59SSivaprasad Tummala  * needed by writing the sys file.
363*6f987b59SSivaprasad Tummala  */
364*6f987b59SSivaprasad Tummala static int
365*6f987b59SSivaprasad Tummala power_set_governor_original(struct pstate_power_info *pi)
366*6f987b59SSivaprasad Tummala {
367*6f987b59SSivaprasad Tummala 	return power_set_governor(pi->lcore_id, pi->governor_ori, NULL, 0);
368*6f987b59SSivaprasad Tummala }
369*6f987b59SSivaprasad Tummala 
370*6f987b59SSivaprasad Tummala /**
371*6f987b59SSivaprasad Tummala  * It is to get the available frequencies of the specific lcore by reading the
372*6f987b59SSivaprasad Tummala  * sys file.
373*6f987b59SSivaprasad Tummala  */
374*6f987b59SSivaprasad Tummala static int
375*6f987b59SSivaprasad Tummala power_get_available_freqs(struct pstate_power_info *pi)
376*6f987b59SSivaprasad Tummala {
377*6f987b59SSivaprasad Tummala 	FILE *f_min = NULL, *f_max = NULL;
378*6f987b59SSivaprasad Tummala 	int ret = -1;
379*6f987b59SSivaprasad Tummala 	uint32_t sys_min_freq = 0, sys_max_freq = 0, base_max_freq = 0;
380*6f987b59SSivaprasad Tummala 	int config_min_freq, config_max_freq;
381*6f987b59SSivaprasad Tummala 	uint32_t i, num_freqs = 0;
382*6f987b59SSivaprasad Tummala 
383*6f987b59SSivaprasad Tummala 	/* open all files */
384*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_max, "r", POWER_SYSFILE_BASE_MAX_FREQ,
385*6f987b59SSivaprasad Tummala 			pi->lcore_id);
386*6f987b59SSivaprasad Tummala 	if (f_max == NULL) {
387*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
388*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MAX_FREQ);
389*6f987b59SSivaprasad Tummala 		goto out;
390*6f987b59SSivaprasad Tummala 	}
391*6f987b59SSivaprasad Tummala 
392*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_min, "r", POWER_SYSFILE_BASE_MIN_FREQ,
393*6f987b59SSivaprasad Tummala 			pi->lcore_id);
394*6f987b59SSivaprasad Tummala 	if (f_min == NULL) {
395*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
396*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MIN_FREQ);
397*6f987b59SSivaprasad Tummala 		goto out;
398*6f987b59SSivaprasad Tummala 	}
399*6f987b59SSivaprasad Tummala 
400*6f987b59SSivaprasad Tummala 	/* read base ratios */
401*6f987b59SSivaprasad Tummala 	ret = read_core_sysfs_u32(f_max, &sys_max_freq);
402*6f987b59SSivaprasad Tummala 	if (ret < 0) {
403*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Failed to read %s",
404*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MAX_FREQ);
405*6f987b59SSivaprasad Tummala 		goto out;
406*6f987b59SSivaprasad Tummala 	}
407*6f987b59SSivaprasad Tummala 
408*6f987b59SSivaprasad Tummala 	ret = read_core_sysfs_u32(f_min, &sys_min_freq);
409*6f987b59SSivaprasad Tummala 	if (ret < 0) {
410*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Failed to read %s",
411*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_BASE_MIN_FREQ);
412*6f987b59SSivaprasad Tummala 		goto out;
413*6f987b59SSivaprasad Tummala 	}
414*6f987b59SSivaprasad Tummala 
415*6f987b59SSivaprasad Tummala 	/* check for config set by user or application to limit frequency range */
416*6f987b59SSivaprasad Tummala 	config_min_freq = rte_power_pmd_mgmt_get_scaling_freq_min(pi->lcore_id);
417*6f987b59SSivaprasad Tummala 	if (config_min_freq < 0)
418*6f987b59SSivaprasad Tummala 		goto out;
419*6f987b59SSivaprasad Tummala 	config_max_freq = rte_power_pmd_mgmt_get_scaling_freq_max(pi->lcore_id);
420*6f987b59SSivaprasad Tummala 	if (config_max_freq < 0)
421*6f987b59SSivaprasad Tummala 		goto out;
422*6f987b59SSivaprasad Tummala 
423*6f987b59SSivaprasad Tummala 	sys_min_freq = RTE_MAX(sys_min_freq, (uint32_t)config_min_freq);
424*6f987b59SSivaprasad Tummala 	if (config_max_freq > 0) /* Only use config_max_freq if a value has been set */
425*6f987b59SSivaprasad Tummala 		sys_max_freq = RTE_MIN(sys_max_freq, (uint32_t)config_max_freq);
426*6f987b59SSivaprasad Tummala 
427*6f987b59SSivaprasad Tummala 	if (sys_max_freq < sys_min_freq)
428*6f987b59SSivaprasad Tummala 		goto out;
429*6f987b59SSivaprasad Tummala 
430*6f987b59SSivaprasad Tummala 	pi->sys_max_freq = sys_max_freq;
431*6f987b59SSivaprasad Tummala 
432*6f987b59SSivaprasad Tummala 	if (pi->priority_core == 1)
433*6f987b59SSivaprasad Tummala 		base_max_freq = pi->core_base_freq;
434*6f987b59SSivaprasad Tummala 	else
435*6f987b59SSivaprasad Tummala 		base_max_freq = pi->non_turbo_max_ratio * BUS_FREQ;
436*6f987b59SSivaprasad Tummala 
437*6f987b59SSivaprasad Tummala 	POWER_DEBUG_LOG("sys min %u, sys max %u, base_max %u",
438*6f987b59SSivaprasad Tummala 			sys_min_freq,
439*6f987b59SSivaprasad Tummala 			sys_max_freq,
440*6f987b59SSivaprasad Tummala 			base_max_freq);
441*6f987b59SSivaprasad Tummala 
442*6f987b59SSivaprasad Tummala 	if (base_max_freq < sys_max_freq)
443*6f987b59SSivaprasad Tummala 		pi->turbo_available = 1;
444*6f987b59SSivaprasad Tummala 	else
445*6f987b59SSivaprasad Tummala 		pi->turbo_available = 0;
446*6f987b59SSivaprasad Tummala 
447*6f987b59SSivaprasad Tummala 	/* If turbo is available then there is one extra freq bucket
448*6f987b59SSivaprasad Tummala 	 * to store the sys max freq which value is base_max +1
449*6f987b59SSivaprasad Tummala 	 */
450*6f987b59SSivaprasad Tummala 	num_freqs = (RTE_MIN(base_max_freq, sys_max_freq) - sys_min_freq) / BUS_FREQ
451*6f987b59SSivaprasad Tummala 			+ 1 + pi->turbo_available;
452*6f987b59SSivaprasad Tummala 	if (num_freqs >= RTE_MAX_LCORE_FREQS) {
453*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Too many available frequencies: %d",
454*6f987b59SSivaprasad Tummala 				num_freqs);
455*6f987b59SSivaprasad Tummala 		goto out;
456*6f987b59SSivaprasad Tummala 	}
457*6f987b59SSivaprasad Tummala 
458*6f987b59SSivaprasad Tummala 	/* Generate the freq bucket array.
459*6f987b59SSivaprasad Tummala 	 * If turbo is available the freq bucket[0] value is base_max +1
460*6f987b59SSivaprasad Tummala 	 * the bucket[1] is base_max, bucket[2] is base_max - BUS_FREQ
461*6f987b59SSivaprasad Tummala 	 * and so on.
462*6f987b59SSivaprasad Tummala 	 * If turbo is not available bucket[0] is base_max and so on
463*6f987b59SSivaprasad Tummala 	 */
464*6f987b59SSivaprasad Tummala 	for (i = 0, pi->nb_freqs = 0; i < num_freqs; i++) {
465*6f987b59SSivaprasad Tummala 		if ((i == 0) && pi->turbo_available)
466*6f987b59SSivaprasad Tummala 			pi->freqs[pi->nb_freqs++] = RTE_MIN(base_max_freq, sys_max_freq) + 1;
467*6f987b59SSivaprasad Tummala 		else
468*6f987b59SSivaprasad Tummala 			pi->freqs[pi->nb_freqs++] = RTE_MIN(base_max_freq, sys_max_freq) -
469*6f987b59SSivaprasad Tummala 					(i - pi->turbo_available) * BUS_FREQ;
470*6f987b59SSivaprasad Tummala 	}
471*6f987b59SSivaprasad Tummala 
472*6f987b59SSivaprasad Tummala 	ret = 0;
473*6f987b59SSivaprasad Tummala 
474*6f987b59SSivaprasad Tummala 	POWER_DEBUG_LOG("%d frequency(s) of lcore %u are available",
475*6f987b59SSivaprasad Tummala 			num_freqs, pi->lcore_id);
476*6f987b59SSivaprasad Tummala 
477*6f987b59SSivaprasad Tummala out:
478*6f987b59SSivaprasad Tummala 	if (f_min != NULL)
479*6f987b59SSivaprasad Tummala 		fclose(f_min);
480*6f987b59SSivaprasad Tummala 	if (f_max != NULL)
481*6f987b59SSivaprasad Tummala 		fclose(f_max);
482*6f987b59SSivaprasad Tummala 
483*6f987b59SSivaprasad Tummala 	return ret;
484*6f987b59SSivaprasad Tummala }
485*6f987b59SSivaprasad Tummala 
486*6f987b59SSivaprasad Tummala static int
487*6f987b59SSivaprasad Tummala power_get_cur_idx(struct pstate_power_info *pi)
488*6f987b59SSivaprasad Tummala {
489*6f987b59SSivaprasad Tummala 	FILE *f_cur;
490*6f987b59SSivaprasad Tummala 	int ret = -1;
491*6f987b59SSivaprasad Tummala 	uint32_t sys_cur_freq = 0;
492*6f987b59SSivaprasad Tummala 	unsigned int i;
493*6f987b59SSivaprasad Tummala 
494*6f987b59SSivaprasad Tummala 	open_core_sysfs_file(&f_cur, "r", POWER_SYSFILE_CUR_FREQ,
495*6f987b59SSivaprasad Tummala 			pi->lcore_id);
496*6f987b59SSivaprasad Tummala 	if (f_cur == NULL) {
497*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "failed to open %s",
498*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_CUR_FREQ);
499*6f987b59SSivaprasad Tummala 		goto fail;
500*6f987b59SSivaprasad Tummala 	}
501*6f987b59SSivaprasad Tummala 
502*6f987b59SSivaprasad Tummala 	ret = read_core_sysfs_u32(f_cur, &sys_cur_freq);
503*6f987b59SSivaprasad Tummala 	if (ret < 0) {
504*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Failed to read %s",
505*6f987b59SSivaprasad Tummala 				POWER_SYSFILE_CUR_FREQ);
506*6f987b59SSivaprasad Tummala 		goto fail;
507*6f987b59SSivaprasad Tummala 	}
508*6f987b59SSivaprasad Tummala 
509*6f987b59SSivaprasad Tummala 	/* convert the frequency to nearest 100000 value
510*6f987b59SSivaprasad Tummala 	 * Ex: if sys_cur_freq=1396789 then freq_conv=1400000
511*6f987b59SSivaprasad Tummala 	 * Ex: if sys_cur_freq=800030 then freq_conv=800000
512*6f987b59SSivaprasad Tummala 	 * Ex: if sys_cur_freq=800030 then freq_conv=800000
513*6f987b59SSivaprasad Tummala 	 */
514*6f987b59SSivaprasad Tummala 	unsigned int freq_conv = 0;
515*6f987b59SSivaprasad Tummala 	freq_conv = (sys_cur_freq + FREQ_ROUNDING_DELTA)
516*6f987b59SSivaprasad Tummala 				/ ROUND_FREQ_TO_N_100000;
517*6f987b59SSivaprasad Tummala 	freq_conv = freq_conv * ROUND_FREQ_TO_N_100000;
518*6f987b59SSivaprasad Tummala 
519*6f987b59SSivaprasad Tummala 	for (i = 0; i < pi->nb_freqs; i++) {
520*6f987b59SSivaprasad Tummala 		if (freq_conv == pi->freqs[i]) {
521*6f987b59SSivaprasad Tummala 			pi->curr_idx = i;
522*6f987b59SSivaprasad Tummala 			break;
523*6f987b59SSivaprasad Tummala 		}
524*6f987b59SSivaprasad Tummala 	}
525*6f987b59SSivaprasad Tummala 
526*6f987b59SSivaprasad Tummala 	ret = 0;
527*6f987b59SSivaprasad Tummala fail:
528*6f987b59SSivaprasad Tummala 	if (f_cur != NULL)
529*6f987b59SSivaprasad Tummala 		fclose(f_cur);
530*6f987b59SSivaprasad Tummala 	return ret;
531*6f987b59SSivaprasad Tummala }
532*6f987b59SSivaprasad Tummala 
533*6f987b59SSivaprasad Tummala int
534*6f987b59SSivaprasad Tummala power_pstate_cpufreq_check_supported(void)
535*6f987b59SSivaprasad Tummala {
536*6f987b59SSivaprasad Tummala 	return cpufreq_check_scaling_driver(POWER_PSTATE_DRIVER);
537*6f987b59SSivaprasad Tummala }
538*6f987b59SSivaprasad Tummala 
539*6f987b59SSivaprasad Tummala int
540*6f987b59SSivaprasad Tummala power_pstate_cpufreq_init(unsigned int lcore_id)
541*6f987b59SSivaprasad Tummala {
542*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
543*6f987b59SSivaprasad Tummala 	uint32_t exp_state;
544*6f987b59SSivaprasad Tummala 
545*6f987b59SSivaprasad Tummala 	if (!power_pstate_cpufreq_check_supported()) {
546*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "%s driver is not supported",
547*6f987b59SSivaprasad Tummala 				POWER_PSTATE_DRIVER);
548*6f987b59SSivaprasad Tummala 		return -1;
549*6f987b59SSivaprasad Tummala 	}
550*6f987b59SSivaprasad Tummala 
551*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
552*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Lcore id %u can not exceed %u",
553*6f987b59SSivaprasad Tummala 				lcore_id, RTE_MAX_LCORE - 1U);
554*6f987b59SSivaprasad Tummala 		return -1;
555*6f987b59SSivaprasad Tummala 	}
556*6f987b59SSivaprasad Tummala 
557*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
558*6f987b59SSivaprasad Tummala 	exp_state = POWER_IDLE;
559*6f987b59SSivaprasad Tummala 	/* The power in use state works as a guard variable between
560*6f987b59SSivaprasad Tummala 	 * the CPU frequency control initialization and exit process.
561*6f987b59SSivaprasad Tummala 	 * The ACQUIRE memory ordering here pairs with the RELEASE
562*6f987b59SSivaprasad Tummala 	 * ordering below as lock to make sure the frequency operations
563*6f987b59SSivaprasad Tummala 	 * in the critical section are done under the correct state.
564*6f987b59SSivaprasad Tummala 	 */
565*6f987b59SSivaprasad Tummala 	if (!rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state,
566*6f987b59SSivaprasad Tummala 					POWER_ONGOING,
567*6f987b59SSivaprasad Tummala 					rte_memory_order_acquire, rte_memory_order_relaxed)) {
568*6f987b59SSivaprasad Tummala 		POWER_LOG(INFO, "Power management of lcore %u is "
569*6f987b59SSivaprasad Tummala 				"in use", lcore_id);
570*6f987b59SSivaprasad Tummala 		return -1;
571*6f987b59SSivaprasad Tummala 	}
572*6f987b59SSivaprasad Tummala 
573*6f987b59SSivaprasad Tummala 	if (power_get_lcore_mapped_cpu_id(lcore_id, &pi->lcore_id) < 0) {
574*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot get CPU ID mapped for lcore %u", lcore_id);
575*6f987b59SSivaprasad Tummala 		return -1;
576*6f987b59SSivaprasad Tummala 	}
577*6f987b59SSivaprasad Tummala 
578*6f987b59SSivaprasad Tummala 	/* Check and set the governor */
579*6f987b59SSivaprasad Tummala 	if (power_set_governor_performance(pi) < 0) {
580*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot set governor of lcore %u to "
581*6f987b59SSivaprasad Tummala 				"performance", lcore_id);
582*6f987b59SSivaprasad Tummala 		goto fail;
583*6f987b59SSivaprasad Tummala 	}
584*6f987b59SSivaprasad Tummala 	/* Init for setting lcore frequency */
585*6f987b59SSivaprasad Tummala 	if (power_init_for_setting_freq(pi) < 0) {
586*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot init for setting frequency for "
587*6f987b59SSivaprasad Tummala 				"lcore %u", lcore_id);
588*6f987b59SSivaprasad Tummala 		goto fail;
589*6f987b59SSivaprasad Tummala 	}
590*6f987b59SSivaprasad Tummala 
591*6f987b59SSivaprasad Tummala 	/* Get the available frequencies */
592*6f987b59SSivaprasad Tummala 	if (power_get_available_freqs(pi) < 0) {
593*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot get available frequencies of "
594*6f987b59SSivaprasad Tummala 				"lcore %u", lcore_id);
595*6f987b59SSivaprasad Tummala 		goto fail;
596*6f987b59SSivaprasad Tummala 	}
597*6f987b59SSivaprasad Tummala 
598*6f987b59SSivaprasad Tummala 	if (power_get_cur_idx(pi) < 0) {
599*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot get current frequency "
600*6f987b59SSivaprasad Tummala 				"index of lcore %u", lcore_id);
601*6f987b59SSivaprasad Tummala 		goto fail;
602*6f987b59SSivaprasad Tummala 	}
603*6f987b59SSivaprasad Tummala 
604*6f987b59SSivaprasad Tummala 	/* Set freq to max by default */
605*6f987b59SSivaprasad Tummala 	if (power_pstate_cpufreq_freq_max(lcore_id) < 0) {
606*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot set frequency of lcore %u "
607*6f987b59SSivaprasad Tummala 				"to max", lcore_id);
608*6f987b59SSivaprasad Tummala 		goto fail;
609*6f987b59SSivaprasad Tummala 	}
610*6f987b59SSivaprasad Tummala 
611*6f987b59SSivaprasad Tummala 	POWER_LOG(INFO, "Initialized successfully for lcore %u "
612*6f987b59SSivaprasad Tummala 			"power management", lcore_id);
613*6f987b59SSivaprasad Tummala 	exp_state = POWER_ONGOING;
614*6f987b59SSivaprasad Tummala 	rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state, POWER_USED,
615*6f987b59SSivaprasad Tummala 				    rte_memory_order_release, rte_memory_order_relaxed);
616*6f987b59SSivaprasad Tummala 
617*6f987b59SSivaprasad Tummala 	return 0;
618*6f987b59SSivaprasad Tummala 
619*6f987b59SSivaprasad Tummala fail:
620*6f987b59SSivaprasad Tummala 	exp_state = POWER_ONGOING;
621*6f987b59SSivaprasad Tummala 	rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state, POWER_UNKNOWN,
622*6f987b59SSivaprasad Tummala 				    rte_memory_order_release, rte_memory_order_relaxed);
623*6f987b59SSivaprasad Tummala 
624*6f987b59SSivaprasad Tummala 	return -1;
625*6f987b59SSivaprasad Tummala }
626*6f987b59SSivaprasad Tummala 
627*6f987b59SSivaprasad Tummala int
628*6f987b59SSivaprasad Tummala power_pstate_cpufreq_exit(unsigned int lcore_id)
629*6f987b59SSivaprasad Tummala {
630*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
631*6f987b59SSivaprasad Tummala 	uint32_t exp_state;
632*6f987b59SSivaprasad Tummala 
633*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
634*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Lcore id %u can not exceeds %u",
635*6f987b59SSivaprasad Tummala 				lcore_id, RTE_MAX_LCORE - 1U);
636*6f987b59SSivaprasad Tummala 		return -1;
637*6f987b59SSivaprasad Tummala 	}
638*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
639*6f987b59SSivaprasad Tummala 
640*6f987b59SSivaprasad Tummala 	exp_state = POWER_USED;
641*6f987b59SSivaprasad Tummala 	/* The power in use state works as a guard variable between
642*6f987b59SSivaprasad Tummala 	 * the CPU frequency control initialization and exit process.
643*6f987b59SSivaprasad Tummala 	 * The ACQUIRE memory ordering here pairs with the RELEASE
644*6f987b59SSivaprasad Tummala 	 * ordering below as lock to make sure the frequency operations
645*6f987b59SSivaprasad Tummala 	 * in the critical section are under done the correct state.
646*6f987b59SSivaprasad Tummala 	 */
647*6f987b59SSivaprasad Tummala 	if (!rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state,
648*6f987b59SSivaprasad Tummala 					POWER_ONGOING,
649*6f987b59SSivaprasad Tummala 					rte_memory_order_acquire, rte_memory_order_relaxed)) {
650*6f987b59SSivaprasad Tummala 		POWER_LOG(INFO, "Power management of lcore %u is "
651*6f987b59SSivaprasad Tummala 				"not used", lcore_id);
652*6f987b59SSivaprasad Tummala 		return -1;
653*6f987b59SSivaprasad Tummala 	}
654*6f987b59SSivaprasad Tummala 
655*6f987b59SSivaprasad Tummala 	/* Close FD of setting freq */
656*6f987b59SSivaprasad Tummala 	fclose(pi->f_cur_min);
657*6f987b59SSivaprasad Tummala 	fclose(pi->f_cur_max);
658*6f987b59SSivaprasad Tummala 	pi->f_cur_min = NULL;
659*6f987b59SSivaprasad Tummala 	pi->f_cur_max = NULL;
660*6f987b59SSivaprasad Tummala 
661*6f987b59SSivaprasad Tummala 	/* Set the governor back to the original */
662*6f987b59SSivaprasad Tummala 	if (power_set_governor_original(pi) < 0) {
663*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Cannot set the governor of %u back "
664*6f987b59SSivaprasad Tummala 				"to the original", lcore_id);
665*6f987b59SSivaprasad Tummala 		goto fail;
666*6f987b59SSivaprasad Tummala 	}
667*6f987b59SSivaprasad Tummala 
668*6f987b59SSivaprasad Tummala 	POWER_LOG(INFO, "Power management of lcore %u has exited from "
669*6f987b59SSivaprasad Tummala 			"'performance' mode and been set back to the "
670*6f987b59SSivaprasad Tummala 			"original", lcore_id);
671*6f987b59SSivaprasad Tummala 	exp_state = POWER_ONGOING;
672*6f987b59SSivaprasad Tummala 	rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state, POWER_IDLE,
673*6f987b59SSivaprasad Tummala 				    rte_memory_order_release, rte_memory_order_relaxed);
674*6f987b59SSivaprasad Tummala 
675*6f987b59SSivaprasad Tummala 	return 0;
676*6f987b59SSivaprasad Tummala 
677*6f987b59SSivaprasad Tummala fail:
678*6f987b59SSivaprasad Tummala 	exp_state = POWER_ONGOING;
679*6f987b59SSivaprasad Tummala 	rte_atomic_compare_exchange_strong_explicit(&(pi->state), &exp_state, POWER_UNKNOWN,
680*6f987b59SSivaprasad Tummala 				    rte_memory_order_release, rte_memory_order_relaxed);
681*6f987b59SSivaprasad Tummala 
682*6f987b59SSivaprasad Tummala 	return -1;
683*6f987b59SSivaprasad Tummala }
684*6f987b59SSivaprasad Tummala 
685*6f987b59SSivaprasad Tummala 
686*6f987b59SSivaprasad Tummala uint32_t
687*6f987b59SSivaprasad Tummala power_pstate_cpufreq_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t num)
688*6f987b59SSivaprasad Tummala {
689*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
690*6f987b59SSivaprasad Tummala 
691*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
692*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
693*6f987b59SSivaprasad Tummala 		return 0;
694*6f987b59SSivaprasad Tummala 	}
695*6f987b59SSivaprasad Tummala 
696*6f987b59SSivaprasad Tummala 	if (freqs == NULL) {
697*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "NULL buffer supplied");
698*6f987b59SSivaprasad Tummala 		return 0;
699*6f987b59SSivaprasad Tummala 	}
700*6f987b59SSivaprasad Tummala 
701*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
702*6f987b59SSivaprasad Tummala 	if (num < pi->nb_freqs) {
703*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Buffer size is not enough");
704*6f987b59SSivaprasad Tummala 		return 0;
705*6f987b59SSivaprasad Tummala 	}
706*6f987b59SSivaprasad Tummala 	rte_memcpy(freqs, pi->freqs, pi->nb_freqs * sizeof(uint32_t));
707*6f987b59SSivaprasad Tummala 
708*6f987b59SSivaprasad Tummala 	return pi->nb_freqs;
709*6f987b59SSivaprasad Tummala }
710*6f987b59SSivaprasad Tummala 
711*6f987b59SSivaprasad Tummala uint32_t
712*6f987b59SSivaprasad Tummala power_pstate_cpufreq_get_freq(unsigned int lcore_id)
713*6f987b59SSivaprasad Tummala {
714*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
715*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
716*6f987b59SSivaprasad Tummala 		return RTE_POWER_INVALID_FREQ_INDEX;
717*6f987b59SSivaprasad Tummala 	}
718*6f987b59SSivaprasad Tummala 
719*6f987b59SSivaprasad Tummala 	return lcore_power_info[lcore_id].curr_idx;
720*6f987b59SSivaprasad Tummala }
721*6f987b59SSivaprasad Tummala 
722*6f987b59SSivaprasad Tummala 
723*6f987b59SSivaprasad Tummala int
724*6f987b59SSivaprasad Tummala power_pstate_cpufreq_set_freq(unsigned int lcore_id, uint32_t index)
725*6f987b59SSivaprasad Tummala {
726*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
727*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
728*6f987b59SSivaprasad Tummala 		return -1;
729*6f987b59SSivaprasad Tummala 	}
730*6f987b59SSivaprasad Tummala 
731*6f987b59SSivaprasad Tummala 	return set_freq_internal(&(lcore_power_info[lcore_id]), index);
732*6f987b59SSivaprasad Tummala }
733*6f987b59SSivaprasad Tummala 
734*6f987b59SSivaprasad Tummala int
735*6f987b59SSivaprasad Tummala power_pstate_cpufreq_freq_up(unsigned int lcore_id)
736*6f987b59SSivaprasad Tummala {
737*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
738*6f987b59SSivaprasad Tummala 
739*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
740*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
741*6f987b59SSivaprasad Tummala 		return -1;
742*6f987b59SSivaprasad Tummala 	}
743*6f987b59SSivaprasad Tummala 
744*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
745*6f987b59SSivaprasad Tummala 	if (pi->curr_idx == 0 ||
746*6f987b59SSivaprasad Tummala 	    (pi->curr_idx == 1 && pi->turbo_available && !pi->turbo_enable))
747*6f987b59SSivaprasad Tummala 		return 0;
748*6f987b59SSivaprasad Tummala 
749*6f987b59SSivaprasad Tummala 	/* Frequencies in the array are from high to low. */
750*6f987b59SSivaprasad Tummala 	return set_freq_internal(pi, pi->curr_idx - 1);
751*6f987b59SSivaprasad Tummala }
752*6f987b59SSivaprasad Tummala 
753*6f987b59SSivaprasad Tummala int
754*6f987b59SSivaprasad Tummala power_pstate_cpufreq_freq_down(unsigned int lcore_id)
755*6f987b59SSivaprasad Tummala {
756*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
757*6f987b59SSivaprasad Tummala 
758*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
759*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
760*6f987b59SSivaprasad Tummala 		return -1;
761*6f987b59SSivaprasad Tummala 	}
762*6f987b59SSivaprasad Tummala 
763*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
764*6f987b59SSivaprasad Tummala 	if (pi->curr_idx + 1 == pi->nb_freqs)
765*6f987b59SSivaprasad Tummala 		return 0;
766*6f987b59SSivaprasad Tummala 
767*6f987b59SSivaprasad Tummala 	/* Frequencies in the array are from high to low. */
768*6f987b59SSivaprasad Tummala 	return set_freq_internal(pi, pi->curr_idx + 1);
769*6f987b59SSivaprasad Tummala }
770*6f987b59SSivaprasad Tummala 
771*6f987b59SSivaprasad Tummala int
772*6f987b59SSivaprasad Tummala power_pstate_cpufreq_freq_max(unsigned int lcore_id)
773*6f987b59SSivaprasad Tummala {
774*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
775*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
776*6f987b59SSivaprasad Tummala 		return -1;
777*6f987b59SSivaprasad Tummala 	}
778*6f987b59SSivaprasad Tummala 
779*6f987b59SSivaprasad Tummala 	/* Frequencies in the array are from high to low. */
780*6f987b59SSivaprasad Tummala 	if (lcore_power_info[lcore_id].turbo_available) {
781*6f987b59SSivaprasad Tummala 		if (lcore_power_info[lcore_id].turbo_enable)
782*6f987b59SSivaprasad Tummala 			/* Set to Turbo */
783*6f987b59SSivaprasad Tummala 			return set_freq_internal(
784*6f987b59SSivaprasad Tummala 					&lcore_power_info[lcore_id], 0);
785*6f987b59SSivaprasad Tummala 		else
786*6f987b59SSivaprasad Tummala 			/* Set to max non-turbo */
787*6f987b59SSivaprasad Tummala 			return set_freq_internal(
788*6f987b59SSivaprasad Tummala 					&lcore_power_info[lcore_id], 1);
789*6f987b59SSivaprasad Tummala 	} else
790*6f987b59SSivaprasad Tummala 		return set_freq_internal(&lcore_power_info[lcore_id], 0);
791*6f987b59SSivaprasad Tummala }
792*6f987b59SSivaprasad Tummala 
793*6f987b59SSivaprasad Tummala 
794*6f987b59SSivaprasad Tummala int
795*6f987b59SSivaprasad Tummala power_pstate_cpufreq_freq_min(unsigned int lcore_id)
796*6f987b59SSivaprasad Tummala {
797*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
798*6f987b59SSivaprasad Tummala 
799*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
800*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
801*6f987b59SSivaprasad Tummala 		return -1;
802*6f987b59SSivaprasad Tummala 	}
803*6f987b59SSivaprasad Tummala 
804*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
805*6f987b59SSivaprasad Tummala 
806*6f987b59SSivaprasad Tummala 	/* Frequencies in the array are from high to low. */
807*6f987b59SSivaprasad Tummala 	return set_freq_internal(pi, pi->nb_freqs - 1);
808*6f987b59SSivaprasad Tummala }
809*6f987b59SSivaprasad Tummala 
810*6f987b59SSivaprasad Tummala 
811*6f987b59SSivaprasad Tummala int
812*6f987b59SSivaprasad Tummala power_pstate_turbo_status(unsigned int lcore_id)
813*6f987b59SSivaprasad Tummala {
814*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
815*6f987b59SSivaprasad Tummala 
816*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
817*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
818*6f987b59SSivaprasad Tummala 		return -1;
819*6f987b59SSivaprasad Tummala 	}
820*6f987b59SSivaprasad Tummala 
821*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
822*6f987b59SSivaprasad Tummala 
823*6f987b59SSivaprasad Tummala 	return pi->turbo_enable;
824*6f987b59SSivaprasad Tummala }
825*6f987b59SSivaprasad Tummala 
826*6f987b59SSivaprasad Tummala int
827*6f987b59SSivaprasad Tummala power_pstate_enable_turbo(unsigned int lcore_id)
828*6f987b59SSivaprasad Tummala {
829*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
830*6f987b59SSivaprasad Tummala 
831*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
832*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
833*6f987b59SSivaprasad Tummala 		return -1;
834*6f987b59SSivaprasad Tummala 	}
835*6f987b59SSivaprasad Tummala 
836*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
837*6f987b59SSivaprasad Tummala 
838*6f987b59SSivaprasad Tummala 	if (pi->turbo_available)
839*6f987b59SSivaprasad Tummala 		pi->turbo_enable = 1;
840*6f987b59SSivaprasad Tummala 	else {
841*6f987b59SSivaprasad Tummala 		pi->turbo_enable = 0;
842*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR,
843*6f987b59SSivaprasad Tummala 			"Failed to enable turbo on lcore %u",
844*6f987b59SSivaprasad Tummala 			lcore_id);
845*6f987b59SSivaprasad Tummala 			return -1;
846*6f987b59SSivaprasad Tummala 	}
847*6f987b59SSivaprasad Tummala 
848*6f987b59SSivaprasad Tummala 	return 0;
849*6f987b59SSivaprasad Tummala }
850*6f987b59SSivaprasad Tummala 
851*6f987b59SSivaprasad Tummala 
852*6f987b59SSivaprasad Tummala int
853*6f987b59SSivaprasad Tummala power_pstate_disable_turbo(unsigned int lcore_id)
854*6f987b59SSivaprasad Tummala {
855*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
856*6f987b59SSivaprasad Tummala 
857*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
858*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
859*6f987b59SSivaprasad Tummala 		return -1;
860*6f987b59SSivaprasad Tummala 	}
861*6f987b59SSivaprasad Tummala 
862*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
863*6f987b59SSivaprasad Tummala 
864*6f987b59SSivaprasad Tummala 	pi->turbo_enable = 0;
865*6f987b59SSivaprasad Tummala 
866*6f987b59SSivaprasad Tummala 	if (pi->turbo_available && pi->curr_idx <= 1) {
867*6f987b59SSivaprasad Tummala 		/* Try to set freq to max by default coming out of turbo */
868*6f987b59SSivaprasad Tummala 		if (power_pstate_cpufreq_freq_max(lcore_id) < 0) {
869*6f987b59SSivaprasad Tummala 			POWER_LOG(ERR,
870*6f987b59SSivaprasad Tummala 				"Failed to set frequency of lcore %u to max",
871*6f987b59SSivaprasad Tummala 				lcore_id);
872*6f987b59SSivaprasad Tummala 			return -1;
873*6f987b59SSivaprasad Tummala 		}
874*6f987b59SSivaprasad Tummala 	}
875*6f987b59SSivaprasad Tummala 
876*6f987b59SSivaprasad Tummala 	return 0;
877*6f987b59SSivaprasad Tummala }
878*6f987b59SSivaprasad Tummala 
879*6f987b59SSivaprasad Tummala 
880*6f987b59SSivaprasad Tummala int power_pstate_get_capabilities(unsigned int lcore_id,
881*6f987b59SSivaprasad Tummala 		struct rte_power_core_capabilities *caps)
882*6f987b59SSivaprasad Tummala {
883*6f987b59SSivaprasad Tummala 	struct pstate_power_info *pi;
884*6f987b59SSivaprasad Tummala 
885*6f987b59SSivaprasad Tummala 	if (lcore_id >= RTE_MAX_LCORE) {
886*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid lcore ID");
887*6f987b59SSivaprasad Tummala 		return -1;
888*6f987b59SSivaprasad Tummala 	}
889*6f987b59SSivaprasad Tummala 	if (caps == NULL) {
890*6f987b59SSivaprasad Tummala 		POWER_LOG(ERR, "Invalid argument");
891*6f987b59SSivaprasad Tummala 		return -1;
892*6f987b59SSivaprasad Tummala 	}
893*6f987b59SSivaprasad Tummala 
894*6f987b59SSivaprasad Tummala 	pi = &lcore_power_info[lcore_id];
895*6f987b59SSivaprasad Tummala 	caps->capabilities = 0;
896*6f987b59SSivaprasad Tummala 	caps->turbo = !!(pi->turbo_available);
897*6f987b59SSivaprasad Tummala 	caps->priority = pi->priority_core;
898*6f987b59SSivaprasad Tummala 
899*6f987b59SSivaprasad Tummala 	return 0;
900*6f987b59SSivaprasad Tummala }
901*6f987b59SSivaprasad Tummala 
902*6f987b59SSivaprasad Tummala static struct rte_power_cpufreq_ops pstate_ops = {
903*6f987b59SSivaprasad Tummala 	.name = "intel-pstate",
904*6f987b59SSivaprasad Tummala 	.init = power_pstate_cpufreq_init,
905*6f987b59SSivaprasad Tummala 	.exit = power_pstate_cpufreq_exit,
906*6f987b59SSivaprasad Tummala 	.check_env_support = power_pstate_cpufreq_check_supported,
907*6f987b59SSivaprasad Tummala 	.get_avail_freqs = power_pstate_cpufreq_freqs,
908*6f987b59SSivaprasad Tummala 	.get_freq = power_pstate_cpufreq_get_freq,
909*6f987b59SSivaprasad Tummala 	.set_freq = power_pstate_cpufreq_set_freq,
910*6f987b59SSivaprasad Tummala 	.freq_down = power_pstate_cpufreq_freq_down,
911*6f987b59SSivaprasad Tummala 	.freq_up = power_pstate_cpufreq_freq_up,
912*6f987b59SSivaprasad Tummala 	.freq_max = power_pstate_cpufreq_freq_max,
913*6f987b59SSivaprasad Tummala 	.freq_min = power_pstate_cpufreq_freq_min,
914*6f987b59SSivaprasad Tummala 	.turbo_status = power_pstate_turbo_status,
915*6f987b59SSivaprasad Tummala 	.enable_turbo = power_pstate_enable_turbo,
916*6f987b59SSivaprasad Tummala 	.disable_turbo = power_pstate_disable_turbo,
917*6f987b59SSivaprasad Tummala 	.get_caps = power_pstate_get_capabilities
918*6f987b59SSivaprasad Tummala };
919*6f987b59SSivaprasad Tummala 
920*6f987b59SSivaprasad Tummala RTE_POWER_REGISTER_CPUFREQ_OPS(pstate_ops);
921