xref: /dpdk/examples/vm_power_manager/power_manager.c (revision 95f648ff9eedc11f9c888f2cc331aadb95cb9b47)
13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause
23998e2a0SBruce Richardson  * Copyright(c) 2010-2014 Intel Corporation
3d26c18c9SAlan Carew  */
4d26c18c9SAlan Carew 
5d26c18c9SAlan Carew #include <stdio.h>
6d26c18c9SAlan Carew #include <stdlib.h>
7d26c18c9SAlan Carew #include <stdint.h>
8d26c18c9SAlan Carew #include <inttypes.h>
9d26c18c9SAlan Carew #include <fcntl.h>
10d26c18c9SAlan Carew #include <unistd.h>
11d26c18c9SAlan Carew #include <dirent.h>
12d26c18c9SAlan Carew #include <errno.h>
13d26c18c9SAlan Carew 
1499a968faSDavid Hunt #include <sys/sysinfo.h>
15d26c18c9SAlan Carew #include <sys/types.h>
16d26c18c9SAlan Carew 
17d26c18c9SAlan Carew #include <rte_log.h>
18d26c18c9SAlan Carew #include <rte_power.h>
19d26c18c9SAlan Carew #include <rte_spinlock.h>
20d26c18c9SAlan Carew 
216453b928SDavid Hunt #include "channel_manager.h"
22d26c18c9SAlan Carew #include "power_manager.h"
236453b928SDavid Hunt #include "oob_monitor.h"
24d26c18c9SAlan Carew 
25d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \
266453b928SDavid Hunt 	if (core_num >= ci.core_count) \
27d26c18c9SAlan Carew 		return -1; \
286453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus)) \
29d26c18c9SAlan Carew 		return -1; \
30d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \
31d26c18c9SAlan Carew 	ret = rte_power_freq_##DIRECTION(core_num); \
32d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \
33d26c18c9SAlan Carew } while (0)
34d26c18c9SAlan Carew 
35d26c18c9SAlan Carew struct freq_info {
36d26c18c9SAlan Carew 	rte_spinlock_t power_sl;
37d26c18c9SAlan Carew 	uint32_t freqs[RTE_MAX_LCORE_FREQS];
38d26c18c9SAlan Carew 	unsigned num_freqs;
39d26c18c9SAlan Carew } __rte_cache_aligned;
40d26c18c9SAlan Carew 
41751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE];
42d26c18c9SAlan Carew 
4399a968faSDavid Hunt struct core_info ci;
44d26c18c9SAlan Carew 
45d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id"
46d26c18c9SAlan Carew 
4799a968faSDavid Hunt struct core_info *
4899a968faSDavid Hunt get_core_info(void)
4999a968faSDavid Hunt {
5099a968faSDavid Hunt 	return &ci;
5199a968faSDavid Hunt }
5299a968faSDavid Hunt 
5399a968faSDavid Hunt int
5499a968faSDavid Hunt core_info_init(void)
5599a968faSDavid Hunt {
5699a968faSDavid Hunt 	struct core_info *ci;
5799a968faSDavid Hunt 	int i;
5899a968faSDavid Hunt 
5999a968faSDavid Hunt 	ci = get_core_info();
6099a968faSDavid Hunt 
6199a968faSDavid Hunt 	ci->core_count = get_nprocs_conf();
6299a968faSDavid Hunt 	ci->cd = malloc(ci->core_count * sizeof(struct core_details));
6331c9a664SDavid Hunt 	memset(ci->cd, 0, ci->core_count * sizeof(struct core_details));
6499a968faSDavid Hunt 	if (!ci->cd) {
6599a968faSDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info.");
6699a968faSDavid Hunt 		return -1;
6799a968faSDavid Hunt 	}
6899a968faSDavid Hunt 	for (i = 0; i < ci->core_count; i++) {
6999a968faSDavid Hunt 		ci->cd[i].global_enabled_cpus = 1;
70*95f648ffSRory Sexton 		ci->cd[i].branch_ratio_threshold = BRANCH_RATIO_THRESHOLD;
7199a968faSDavid Hunt 	}
7299a968faSDavid Hunt 	printf("%d cores in system\n", ci->core_count);
7399a968faSDavid Hunt 	return 0;
7499a968faSDavid Hunt }
7599a968faSDavid Hunt 
76d26c18c9SAlan Carew int
77d26c18c9SAlan Carew power_manager_init(void)
78d26c18c9SAlan Carew {
796453b928SDavid Hunt 	unsigned int i, num_cpus = 0, num_freqs = 0;
80d26c18c9SAlan Carew 	int ret = 0;
816453b928SDavid Hunt 	struct core_info *ci;
82c12ade20SDavid Hunt 	unsigned int max_core_num;
83d26c18c9SAlan Carew 
846ff7b996SDavid Hunt 	rte_power_set_env(PM_ENV_NOT_SET);
856453b928SDavid Hunt 
866453b928SDavid Hunt 	ci = get_core_info();
876453b928SDavid Hunt 	if (!ci) {
886453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
896453b928SDavid Hunt 				"Failed to get core info!\n");
90d26c18c9SAlan Carew 		return -1;
91d26c18c9SAlan Carew 	}
926453b928SDavid Hunt 
93751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
94751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
95c12ade20SDavid Hunt 	else
96c12ade20SDavid Hunt 		max_core_num = ci->core_count;
97c12ade20SDavid Hunt 
98c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
996453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
1007f472f74SDavid Hunt 			if (rte_power_init(i) < 0)
1017f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1027f472f74SDavid Hunt 						"Unable to initialize power manager "
103d26c18c9SAlan Carew 						"for core %u\n", i);
1046453b928SDavid Hunt 			num_cpus++;
1056453b928SDavid Hunt 			num_freqs = rte_power_freqs(i,
1066453b928SDavid Hunt 					global_core_freq_info[i].freqs,
1077f472f74SDavid Hunt 					RTE_MAX_LCORE_FREQS);
1087f472f74SDavid Hunt 			if (num_freqs == 0) {
1097f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1107f472f74SDavid Hunt 					"Unable to get frequency list for core %u\n",
1117f472f74SDavid Hunt 					i);
1126453b928SDavid Hunt 				ci->cd[i].oob_enabled = 0;
113d26c18c9SAlan Carew 				ret = -1;
114d26c18c9SAlan Carew 			}
1157f472f74SDavid Hunt 			global_core_freq_info[i].num_freqs = num_freqs;
1166453b928SDavid Hunt 
117d26c18c9SAlan Carew 			rte_spinlock_init(&global_core_freq_info[i].power_sl);
118d26c18c9SAlan Carew 		}
1196453b928SDavid Hunt 		if (ci->cd[i].oob_enabled)
1206453b928SDavid Hunt 			add_core_to_monitor(i);
1216453b928SDavid Hunt 	}
1226453b928SDavid Hunt 	RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n",
1236453b928SDavid Hunt 			num_cpus, ci->core_count);
124d26c18c9SAlan Carew 	return ret;
125d26c18c9SAlan Carew 
126d26c18c9SAlan Carew }
127d26c18c9SAlan Carew 
128d26c18c9SAlan Carew uint32_t
129d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num)
130d26c18c9SAlan Carew {
131d26c18c9SAlan Carew 	uint32_t freq, index;
132d26c18c9SAlan Carew 
133751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE) {
134d26c18c9SAlan Carew 		RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n",
135751227a0SDavid Hunt 				core_num, RTE_MAX_LCORE-1);
136d26c18c9SAlan Carew 		return -1;
137d26c18c9SAlan Carew 	}
1386453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus))
139d26c18c9SAlan Carew 		return 0;
140d26c18c9SAlan Carew 
141d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
142d26c18c9SAlan Carew 	index = rte_power_get_freq(core_num);
143d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
1443f1fc5f2SDavid Hunt 	if (index >= RTE_MAX_LCORE_FREQS)
145d26c18c9SAlan Carew 		freq = 0;
146d26c18c9SAlan Carew 	else
147d26c18c9SAlan Carew 		freq = global_core_freq_info[core_num].freqs[index];
148d26c18c9SAlan Carew 
149d26c18c9SAlan Carew 	return freq;
150d26c18c9SAlan Carew }
151d26c18c9SAlan Carew 
152d26c18c9SAlan Carew int
153d26c18c9SAlan Carew power_manager_exit(void)
154d26c18c9SAlan Carew {
155d26c18c9SAlan Carew 	unsigned int i;
156d26c18c9SAlan Carew 	int ret = 0;
1576453b928SDavid Hunt 	struct core_info *ci;
158c12ade20SDavid Hunt 	unsigned int max_core_num;
159d26c18c9SAlan Carew 
1606453b928SDavid Hunt 	ci = get_core_info();
1616453b928SDavid Hunt 	if (!ci) {
1626453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
1636453b928SDavid Hunt 				"Failed to get core info!\n");
1646453b928SDavid Hunt 		return -1;
1656453b928SDavid Hunt 	}
1666453b928SDavid Hunt 
167751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
168751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
169c12ade20SDavid Hunt 	else
170c12ade20SDavid Hunt 		max_core_num = ci->core_count;
171c12ade20SDavid Hunt 
172c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
1736453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
174d26c18c9SAlan Carew 			if (rte_power_exit(i) < 0) {
175d26c18c9SAlan Carew 				RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager "
176d26c18c9SAlan Carew 						"for core %u\n", i);
177d26c18c9SAlan Carew 				ret = -1;
178d26c18c9SAlan Carew 			}
1796453b928SDavid Hunt 			ci->cd[i].global_enabled_cpus = 0;
180d26c18c9SAlan Carew 		}
1816453b928SDavid Hunt 		remove_core_from_monitor(i);
1826453b928SDavid Hunt 	}
183d26c18c9SAlan Carew 	return ret;
184d26c18c9SAlan Carew }
185d26c18c9SAlan Carew 
186d26c18c9SAlan Carew int
187d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num)
188d26c18c9SAlan Carew {
189d26c18c9SAlan Carew 	int ret = 0;
190d26c18c9SAlan Carew 
191d26c18c9SAlan Carew 	POWER_SCALE_CORE(up, core_num, ret);
192d26c18c9SAlan Carew 	return ret;
193d26c18c9SAlan Carew }
194d26c18c9SAlan Carew 
195d26c18c9SAlan Carew int
196d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num)
197d26c18c9SAlan Carew {
198d26c18c9SAlan Carew 	int ret = 0;
199d26c18c9SAlan Carew 
200d26c18c9SAlan Carew 	POWER_SCALE_CORE(down, core_num, ret);
201d26c18c9SAlan Carew 	return ret;
202d26c18c9SAlan Carew }
203d26c18c9SAlan Carew 
204d26c18c9SAlan Carew int
205d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num)
206d26c18c9SAlan Carew {
207d26c18c9SAlan Carew 	int ret = 0;
208d26c18c9SAlan Carew 
209d26c18c9SAlan Carew 	POWER_SCALE_CORE(min, core_num, ret);
210d26c18c9SAlan Carew 	return ret;
211d26c18c9SAlan Carew }
212d26c18c9SAlan Carew 
213d26c18c9SAlan Carew int
214d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num)
215d26c18c9SAlan Carew {
216d26c18c9SAlan Carew 	int ret = 0;
217d26c18c9SAlan Carew 
218d26c18c9SAlan Carew 	POWER_SCALE_CORE(max, core_num, ret);
219d26c18c9SAlan Carew 	return ret;
220d26c18c9SAlan Carew }
221567997b9SDavid Hunt 
222567997b9SDavid Hunt int
223567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num)
224567997b9SDavid Hunt {
225567997b9SDavid Hunt 	int ret = 0;
226567997b9SDavid Hunt 
227567997b9SDavid Hunt 	POWER_SCALE_CORE(enable_turbo, core_num, ret);
228567997b9SDavid Hunt 	return ret;
229567997b9SDavid Hunt }
230567997b9SDavid Hunt 
231567997b9SDavid Hunt int
232567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num)
233567997b9SDavid Hunt {
234567997b9SDavid Hunt 	int ret = 0;
235567997b9SDavid Hunt 
236567997b9SDavid Hunt 	POWER_SCALE_CORE(disable_turbo, core_num, ret);
237567997b9SDavid Hunt 	return ret;
238567997b9SDavid Hunt }
2397f472f74SDavid Hunt 
2407f472f74SDavid Hunt int
2417f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num)
2427f472f74SDavid Hunt {
2437f472f74SDavid Hunt 	int ret = 0;
2446453b928SDavid Hunt 	struct core_info *ci;
2457f472f74SDavid Hunt 
2466453b928SDavid Hunt 	ci = get_core_info();
247751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE)
2487f472f74SDavid Hunt 		return -1;
2496453b928SDavid Hunt 	if (!(ci->cd[core_num].global_enabled_cpus))
2507f472f74SDavid Hunt 		return -1;
2517f472f74SDavid Hunt 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
2527f472f74SDavid Hunt 	ret = rte_power_set_freq(core_num,
2537f472f74SDavid Hunt 				global_core_freq_info[core_num].num_freqs / 2);
2547f472f74SDavid Hunt 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
2557f472f74SDavid Hunt 	return ret;
2567f472f74SDavid Hunt }
257