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