xref: /dpdk/lib/power/rte_power_cpufreq.c (revision f30a1bbd63f494f5ba623582d7e9166c817794a4)
1*f30a1bbdSSivaprasad Tummala /* SPDX-License-Identifier: BSD-3-Clause
2*f30a1bbdSSivaprasad Tummala  * Copyright(c) 2010-2014 Intel Corporation
3*f30a1bbdSSivaprasad Tummala  */
4*f30a1bbdSSivaprasad Tummala 
5*f30a1bbdSSivaprasad Tummala #include <rte_spinlock.h>
6*f30a1bbdSSivaprasad Tummala #include <rte_debug.h>
7*f30a1bbdSSivaprasad Tummala 
8*f30a1bbdSSivaprasad Tummala #include "rte_power_cpufreq.h"
9*f30a1bbdSSivaprasad Tummala #include "power_common.h"
10*f30a1bbdSSivaprasad Tummala 
11*f30a1bbdSSivaprasad Tummala static enum power_management_env global_default_env = PM_ENV_NOT_SET;
12*f30a1bbdSSivaprasad Tummala static struct rte_power_cpufreq_ops *global_cpufreq_ops;
13*f30a1bbdSSivaprasad Tummala 
14*f30a1bbdSSivaprasad Tummala static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER;
15*f30a1bbdSSivaprasad Tummala static RTE_TAILQ_HEAD(, rte_power_cpufreq_ops) cpufreq_ops_list =
16*f30a1bbdSSivaprasad Tummala 			TAILQ_HEAD_INITIALIZER(cpufreq_ops_list);
17*f30a1bbdSSivaprasad Tummala 
18*f30a1bbdSSivaprasad Tummala const char *power_env_str[] = {
19*f30a1bbdSSivaprasad Tummala 	"not set",
20*f30a1bbdSSivaprasad Tummala 	"acpi",
21*f30a1bbdSSivaprasad Tummala 	"kvm-vm",
22*f30a1bbdSSivaprasad Tummala 	"intel-pstate",
23*f30a1bbdSSivaprasad Tummala 	"cppc",
24*f30a1bbdSSivaprasad Tummala 	"amd-pstate"
25*f30a1bbdSSivaprasad Tummala };
26*f30a1bbdSSivaprasad Tummala 
27*f30a1bbdSSivaprasad Tummala /* register the ops struct in rte_power_cpufreq_ops, return 0 on success. */
28*f30a1bbdSSivaprasad Tummala int
29*f30a1bbdSSivaprasad Tummala rte_power_register_cpufreq_ops(struct rte_power_cpufreq_ops *driver_ops)
30*f30a1bbdSSivaprasad Tummala {
31*f30a1bbdSSivaprasad Tummala 	if (!driver_ops->init || !driver_ops->exit ||
32*f30a1bbdSSivaprasad Tummala 		!driver_ops->check_env_support || !driver_ops->get_avail_freqs ||
33*f30a1bbdSSivaprasad Tummala 		!driver_ops->get_freq || !driver_ops->set_freq ||
34*f30a1bbdSSivaprasad Tummala 		!driver_ops->freq_up || !driver_ops->freq_down ||
35*f30a1bbdSSivaprasad Tummala 		!driver_ops->freq_max || !driver_ops->freq_min ||
36*f30a1bbdSSivaprasad Tummala 		!driver_ops->turbo_status || !driver_ops->enable_turbo ||
37*f30a1bbdSSivaprasad Tummala 		!driver_ops->disable_turbo || !driver_ops->get_caps) {
38*f30a1bbdSSivaprasad Tummala 		POWER_LOG(ERR, "Missing callbacks while registering cpufreq ops");
39*f30a1bbdSSivaprasad Tummala 		return -1;
40*f30a1bbdSSivaprasad Tummala 	}
41*f30a1bbdSSivaprasad Tummala 
42*f30a1bbdSSivaprasad Tummala 	TAILQ_INSERT_TAIL(&cpufreq_ops_list, driver_ops, next);
43*f30a1bbdSSivaprasad Tummala 
44*f30a1bbdSSivaprasad Tummala 	return 0;
45*f30a1bbdSSivaprasad Tummala }
46*f30a1bbdSSivaprasad Tummala 
47*f30a1bbdSSivaprasad Tummala int
48*f30a1bbdSSivaprasad Tummala rte_power_check_env_supported(enum power_management_env env)
49*f30a1bbdSSivaprasad Tummala {
50*f30a1bbdSSivaprasad Tummala 	struct rte_power_cpufreq_ops *ops;
51*f30a1bbdSSivaprasad Tummala 
52*f30a1bbdSSivaprasad Tummala 	if (env >= RTE_DIM(power_env_str))
53*f30a1bbdSSivaprasad Tummala 		return 0;
54*f30a1bbdSSivaprasad Tummala 
55*f30a1bbdSSivaprasad Tummala 	RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next)
56*f30a1bbdSSivaprasad Tummala 		if (strncmp(ops->name, power_env_str[env],
57*f30a1bbdSSivaprasad Tummala 				RTE_POWER_DRIVER_NAMESZ) == 0)
58*f30a1bbdSSivaprasad Tummala 			return ops->check_env_support();
59*f30a1bbdSSivaprasad Tummala 
60*f30a1bbdSSivaprasad Tummala 	return 0;
61*f30a1bbdSSivaprasad Tummala }
62*f30a1bbdSSivaprasad Tummala 
63*f30a1bbdSSivaprasad Tummala int
64*f30a1bbdSSivaprasad Tummala rte_power_set_env(enum power_management_env env)
65*f30a1bbdSSivaprasad Tummala {
66*f30a1bbdSSivaprasad Tummala 	struct rte_power_cpufreq_ops *ops;
67*f30a1bbdSSivaprasad Tummala 	int ret = -1;
68*f30a1bbdSSivaprasad Tummala 
69*f30a1bbdSSivaprasad Tummala 	rte_spinlock_lock(&global_env_cfg_lock);
70*f30a1bbdSSivaprasad Tummala 
71*f30a1bbdSSivaprasad Tummala 	if (global_default_env != PM_ENV_NOT_SET) {
72*f30a1bbdSSivaprasad Tummala 		POWER_LOG(ERR, "Power Management Environment already set.");
73*f30a1bbdSSivaprasad Tummala 		goto out;
74*f30a1bbdSSivaprasad Tummala 	}
75*f30a1bbdSSivaprasad Tummala 
76*f30a1bbdSSivaprasad Tummala 	RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next)
77*f30a1bbdSSivaprasad Tummala 		if (strncmp(ops->name, power_env_str[env],
78*f30a1bbdSSivaprasad Tummala 				RTE_POWER_DRIVER_NAMESZ) == 0) {
79*f30a1bbdSSivaprasad Tummala 			global_cpufreq_ops = ops;
80*f30a1bbdSSivaprasad Tummala 			global_default_env = env;
81*f30a1bbdSSivaprasad Tummala 			ret = 0;
82*f30a1bbdSSivaprasad Tummala 			goto out;
83*f30a1bbdSSivaprasad Tummala 		}
84*f30a1bbdSSivaprasad Tummala 
85*f30a1bbdSSivaprasad Tummala 	POWER_LOG(ERR, "Invalid Power Management Environment(%d) set",
86*f30a1bbdSSivaprasad Tummala 			env);
87*f30a1bbdSSivaprasad Tummala out:
88*f30a1bbdSSivaprasad Tummala 	rte_spinlock_unlock(&global_env_cfg_lock);
89*f30a1bbdSSivaprasad Tummala 	return ret;
90*f30a1bbdSSivaprasad Tummala }
91*f30a1bbdSSivaprasad Tummala 
92*f30a1bbdSSivaprasad Tummala void
93*f30a1bbdSSivaprasad Tummala rte_power_unset_env(void)
94*f30a1bbdSSivaprasad Tummala {
95*f30a1bbdSSivaprasad Tummala 	rte_spinlock_lock(&global_env_cfg_lock);
96*f30a1bbdSSivaprasad Tummala 	global_default_env = PM_ENV_NOT_SET;
97*f30a1bbdSSivaprasad Tummala 	global_cpufreq_ops = NULL;
98*f30a1bbdSSivaprasad Tummala 	rte_spinlock_unlock(&global_env_cfg_lock);
99*f30a1bbdSSivaprasad Tummala }
100*f30a1bbdSSivaprasad Tummala 
101*f30a1bbdSSivaprasad Tummala enum power_management_env
102*f30a1bbdSSivaprasad Tummala rte_power_get_env(void) {
103*f30a1bbdSSivaprasad Tummala 	return global_default_env;
104*f30a1bbdSSivaprasad Tummala }
105*f30a1bbdSSivaprasad Tummala 
106*f30a1bbdSSivaprasad Tummala int
107*f30a1bbdSSivaprasad Tummala rte_power_init(unsigned int lcore_id)
108*f30a1bbdSSivaprasad Tummala {
109*f30a1bbdSSivaprasad Tummala 	struct rte_power_cpufreq_ops *ops;
110*f30a1bbdSSivaprasad Tummala 	uint8_t env;
111*f30a1bbdSSivaprasad Tummala 
112*f30a1bbdSSivaprasad Tummala 	if (global_default_env != PM_ENV_NOT_SET)
113*f30a1bbdSSivaprasad Tummala 		return global_cpufreq_ops->init(lcore_id);
114*f30a1bbdSSivaprasad Tummala 
115*f30a1bbdSSivaprasad Tummala 	POWER_LOG(INFO, "Env isn't set yet!");
116*f30a1bbdSSivaprasad Tummala 
117*f30a1bbdSSivaprasad Tummala 	/* Auto detect Environment */
118*f30a1bbdSSivaprasad Tummala 	RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next) {
119*f30a1bbdSSivaprasad Tummala 		POWER_LOG(INFO,
120*f30a1bbdSSivaprasad Tummala 			"Attempting to initialise %s cpufreq power management...",
121*f30a1bbdSSivaprasad Tummala 			ops->name);
122*f30a1bbdSSivaprasad Tummala 		for (env = 0; env < RTE_DIM(power_env_str); env++) {
123*f30a1bbdSSivaprasad Tummala 			if ((strncmp(ops->name, power_env_str[env],
124*f30a1bbdSSivaprasad Tummala 				RTE_POWER_DRIVER_NAMESZ) == 0) &&
125*f30a1bbdSSivaprasad Tummala 				(ops->init(lcore_id) == 0)) {
126*f30a1bbdSSivaprasad Tummala 				rte_power_set_env(env);
127*f30a1bbdSSivaprasad Tummala 				return 0;
128*f30a1bbdSSivaprasad Tummala 			}
129*f30a1bbdSSivaprasad Tummala 		}
130*f30a1bbdSSivaprasad Tummala 	}
131*f30a1bbdSSivaprasad Tummala 
132*f30a1bbdSSivaprasad Tummala 	POWER_LOG(ERR,
133*f30a1bbdSSivaprasad Tummala 		"Unable to set Power Management Environment for lcore %u",
134*f30a1bbdSSivaprasad Tummala 		lcore_id);
135*f30a1bbdSSivaprasad Tummala 
136*f30a1bbdSSivaprasad Tummala 	return -1;
137*f30a1bbdSSivaprasad Tummala }
138*f30a1bbdSSivaprasad Tummala 
139*f30a1bbdSSivaprasad Tummala int
140*f30a1bbdSSivaprasad Tummala rte_power_exit(unsigned int lcore_id)
141*f30a1bbdSSivaprasad Tummala {
142*f30a1bbdSSivaprasad Tummala 	if (global_default_env != PM_ENV_NOT_SET)
143*f30a1bbdSSivaprasad Tummala 		return global_cpufreq_ops->exit(lcore_id);
144*f30a1bbdSSivaprasad Tummala 
145*f30a1bbdSSivaprasad Tummala 	POWER_LOG(ERR,
146*f30a1bbdSSivaprasad Tummala 		"Environment has not been set, unable to exit gracefully");
147*f30a1bbdSSivaprasad Tummala 
148*f30a1bbdSSivaprasad Tummala 	return -1;
149*f30a1bbdSSivaprasad Tummala }
150*f30a1bbdSSivaprasad Tummala 
151*f30a1bbdSSivaprasad Tummala uint32_t
152*f30a1bbdSSivaprasad Tummala rte_power_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t n)
153*f30a1bbdSSivaprasad Tummala {
154*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
155*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->get_avail_freqs(lcore_id, freqs, n);
156*f30a1bbdSSivaprasad Tummala }
157*f30a1bbdSSivaprasad Tummala 
158*f30a1bbdSSivaprasad Tummala uint32_t
159*f30a1bbdSSivaprasad Tummala rte_power_get_freq(unsigned int lcore_id)
160*f30a1bbdSSivaprasad Tummala {
161*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
162*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->get_freq(lcore_id);
163*f30a1bbdSSivaprasad Tummala }
164*f30a1bbdSSivaprasad Tummala 
165*f30a1bbdSSivaprasad Tummala uint32_t
166*f30a1bbdSSivaprasad Tummala rte_power_set_freq(unsigned int lcore_id, uint32_t index)
167*f30a1bbdSSivaprasad Tummala {
168*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
169*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->set_freq(lcore_id, index);
170*f30a1bbdSSivaprasad Tummala }
171*f30a1bbdSSivaprasad Tummala 
172*f30a1bbdSSivaprasad Tummala int
173*f30a1bbdSSivaprasad Tummala rte_power_freq_up(unsigned int lcore_id)
174*f30a1bbdSSivaprasad Tummala {
175*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
176*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->freq_up(lcore_id);
177*f30a1bbdSSivaprasad Tummala }
178*f30a1bbdSSivaprasad Tummala 
179*f30a1bbdSSivaprasad Tummala int
180*f30a1bbdSSivaprasad Tummala rte_power_freq_down(unsigned int lcore_id)
181*f30a1bbdSSivaprasad Tummala {
182*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
183*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->freq_down(lcore_id);
184*f30a1bbdSSivaprasad Tummala }
185*f30a1bbdSSivaprasad Tummala 
186*f30a1bbdSSivaprasad Tummala int
187*f30a1bbdSSivaprasad Tummala rte_power_freq_max(unsigned int lcore_id)
188*f30a1bbdSSivaprasad Tummala {
189*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
190*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->freq_max(lcore_id);
191*f30a1bbdSSivaprasad Tummala }
192*f30a1bbdSSivaprasad Tummala 
193*f30a1bbdSSivaprasad Tummala int
194*f30a1bbdSSivaprasad Tummala rte_power_freq_min(unsigned int lcore_id)
195*f30a1bbdSSivaprasad Tummala {
196*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
197*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->freq_min(lcore_id);
198*f30a1bbdSSivaprasad Tummala }
199*f30a1bbdSSivaprasad Tummala 
200*f30a1bbdSSivaprasad Tummala int
201*f30a1bbdSSivaprasad Tummala rte_power_turbo_status(unsigned int lcore_id)
202*f30a1bbdSSivaprasad Tummala {
203*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
204*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->turbo_status(lcore_id);
205*f30a1bbdSSivaprasad Tummala }
206*f30a1bbdSSivaprasad Tummala 
207*f30a1bbdSSivaprasad Tummala int
208*f30a1bbdSSivaprasad Tummala rte_power_freq_enable_turbo(unsigned int lcore_id)
209*f30a1bbdSSivaprasad Tummala {
210*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
211*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->enable_turbo(lcore_id);
212*f30a1bbdSSivaprasad Tummala }
213*f30a1bbdSSivaprasad Tummala 
214*f30a1bbdSSivaprasad Tummala int
215*f30a1bbdSSivaprasad Tummala rte_power_freq_disable_turbo(unsigned int lcore_id)
216*f30a1bbdSSivaprasad Tummala {
217*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
218*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->disable_turbo(lcore_id);
219*f30a1bbdSSivaprasad Tummala }
220*f30a1bbdSSivaprasad Tummala 
221*f30a1bbdSSivaprasad Tummala int
222*f30a1bbdSSivaprasad Tummala rte_power_get_capabilities(unsigned int lcore_id,
223*f30a1bbdSSivaprasad Tummala 		struct rte_power_core_capabilities *caps)
224*f30a1bbdSSivaprasad Tummala {
225*f30a1bbdSSivaprasad Tummala 	RTE_ASSERT(global_cpufreq_ops != NULL);
226*f30a1bbdSSivaprasad Tummala 	return global_cpufreq_ops->get_caps(lcore_id, caps);
227*f30a1bbdSSivaprasad Tummala }
228