xref: /dpdk/examples/vm_power_manager/power_manager.c (revision 3f1fc5f2cbc57ed719f9a1b24c8e450c5a95e8db)
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 <sys/un.h>
10d26c18c9SAlan Carew #include <fcntl.h>
11d26c18c9SAlan Carew #include <unistd.h>
12d26c18c9SAlan Carew #include <dirent.h>
13d26c18c9SAlan Carew #include <errno.h>
14d26c18c9SAlan Carew 
1599a968faSDavid Hunt #include <sys/sysinfo.h>
16d26c18c9SAlan Carew #include <sys/types.h>
17d26c18c9SAlan Carew 
18d26c18c9SAlan Carew #include <rte_log.h>
19d26c18c9SAlan Carew #include <rte_power.h>
20d26c18c9SAlan Carew #include <rte_spinlock.h>
21d26c18c9SAlan Carew 
226453b928SDavid Hunt #include "channel_manager.h"
23d26c18c9SAlan Carew #include "power_manager.h"
246453b928SDavid Hunt #include "oob_monitor.h"
25d26c18c9SAlan Carew 
26d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \
276453b928SDavid Hunt 	if (core_num >= ci.core_count) \
28d26c18c9SAlan Carew 		return -1; \
296453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus)) \
30d26c18c9SAlan Carew 		return -1; \
31d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \
32d26c18c9SAlan Carew 	ret = rte_power_freq_##DIRECTION(core_num); \
33d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \
34d26c18c9SAlan Carew } while (0)
35d26c18c9SAlan Carew 
36d26c18c9SAlan Carew struct freq_info {
37d26c18c9SAlan Carew 	rte_spinlock_t power_sl;
38d26c18c9SAlan Carew 	uint32_t freqs[RTE_MAX_LCORE_FREQS];
39d26c18c9SAlan Carew 	unsigned num_freqs;
40d26c18c9SAlan Carew } __rte_cache_aligned;
41d26c18c9SAlan Carew 
42751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE];
43d26c18c9SAlan Carew 
4499a968faSDavid Hunt struct core_info ci;
45d26c18c9SAlan Carew 
46d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id"
47d26c18c9SAlan Carew 
4899a968faSDavid Hunt struct core_info *
4999a968faSDavid Hunt get_core_info(void)
5099a968faSDavid Hunt {
5199a968faSDavid Hunt 	return &ci;
5299a968faSDavid Hunt }
5399a968faSDavid Hunt 
5499a968faSDavid Hunt int
5599a968faSDavid Hunt core_info_init(void)
5699a968faSDavid Hunt {
5799a968faSDavid Hunt 	struct core_info *ci;
5899a968faSDavid Hunt 	int i;
5999a968faSDavid Hunt 
6099a968faSDavid Hunt 	ci = get_core_info();
6199a968faSDavid Hunt 
6299a968faSDavid Hunt 	ci->core_count = get_nprocs_conf();
63711f43baSDavid Hunt 	ci->branch_ratio_threshold = BRANCH_RATIO_THRESHOLD;
6499a968faSDavid Hunt 	ci->cd = malloc(ci->core_count * sizeof(struct core_details));
6599a968faSDavid Hunt 	if (!ci->cd) {
6699a968faSDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info.");
6799a968faSDavid Hunt 		return -1;
6899a968faSDavid Hunt 	}
6999a968faSDavid Hunt 	for (i = 0; i < ci->core_count; i++) {
7099a968faSDavid Hunt 		ci->cd[i].global_enabled_cpus = 1;
7199a968faSDavid Hunt 		ci->cd[i].oob_enabled = 0;
7299a968faSDavid Hunt 		ci->cd[i].msr_fd = 0;
7399a968faSDavid Hunt 	}
7499a968faSDavid Hunt 	printf("%d cores in system\n", ci->core_count);
7599a968faSDavid Hunt 	return 0;
7699a968faSDavid Hunt }
7799a968faSDavid Hunt 
78d26c18c9SAlan Carew int
79d26c18c9SAlan Carew power_manager_init(void)
80d26c18c9SAlan Carew {
816453b928SDavid Hunt 	unsigned int i, num_cpus = 0, num_freqs = 0;
82d26c18c9SAlan Carew 	int ret = 0;
836453b928SDavid Hunt 	struct core_info *ci;
84c12ade20SDavid Hunt 	unsigned int max_core_num;
85d26c18c9SAlan Carew 
866ff7b996SDavid Hunt 	rte_power_set_env(PM_ENV_NOT_SET);
876453b928SDavid Hunt 
886453b928SDavid Hunt 	ci = get_core_info();
896453b928SDavid Hunt 	if (!ci) {
906453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
916453b928SDavid Hunt 				"Failed to get core info!\n");
92d26c18c9SAlan Carew 		return -1;
93d26c18c9SAlan Carew 	}
946453b928SDavid Hunt 
95751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
96751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
97c12ade20SDavid Hunt 	else
98c12ade20SDavid Hunt 		max_core_num = ci->core_count;
99c12ade20SDavid Hunt 
100c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
1016453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
1027f472f74SDavid Hunt 			if (rte_power_init(i) < 0)
1037f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1047f472f74SDavid Hunt 						"Unable to initialize power manager "
105d26c18c9SAlan Carew 						"for core %u\n", i);
1066453b928SDavid Hunt 			num_cpus++;
1076453b928SDavid Hunt 			num_freqs = rte_power_freqs(i,
1086453b928SDavid Hunt 					global_core_freq_info[i].freqs,
1097f472f74SDavid Hunt 					RTE_MAX_LCORE_FREQS);
1107f472f74SDavid Hunt 			if (num_freqs == 0) {
1117f472f74SDavid Hunt 				RTE_LOG(ERR, POWER_MANAGER,
1127f472f74SDavid Hunt 					"Unable to get frequency list for core %u\n",
1137f472f74SDavid Hunt 					i);
1146453b928SDavid Hunt 				ci->cd[i].oob_enabled = 0;
115d26c18c9SAlan Carew 				ret = -1;
116d26c18c9SAlan Carew 			}
1177f472f74SDavid Hunt 			global_core_freq_info[i].num_freqs = num_freqs;
1186453b928SDavid Hunt 
119d26c18c9SAlan Carew 			rte_spinlock_init(&global_core_freq_info[i].power_sl);
120d26c18c9SAlan Carew 		}
1216453b928SDavid Hunt 		if (ci->cd[i].oob_enabled)
1226453b928SDavid Hunt 			add_core_to_monitor(i);
1236453b928SDavid Hunt 	}
1246453b928SDavid Hunt 	RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n",
1256453b928SDavid Hunt 			num_cpus, ci->core_count);
126d26c18c9SAlan Carew 	return ret;
127d26c18c9SAlan Carew 
128d26c18c9SAlan Carew }
129d26c18c9SAlan Carew 
130d26c18c9SAlan Carew uint32_t
131d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num)
132d26c18c9SAlan Carew {
133d26c18c9SAlan Carew 	uint32_t freq, index;
134d26c18c9SAlan Carew 
135751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE) {
136d26c18c9SAlan Carew 		RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n",
137751227a0SDavid Hunt 				core_num, RTE_MAX_LCORE-1);
138d26c18c9SAlan Carew 		return -1;
139d26c18c9SAlan Carew 	}
1406453b928SDavid Hunt 	if (!(ci.cd[core_num].global_enabled_cpus))
141d26c18c9SAlan Carew 		return 0;
142d26c18c9SAlan Carew 
143d26c18c9SAlan Carew 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
144d26c18c9SAlan Carew 	index = rte_power_get_freq(core_num);
145d26c18c9SAlan Carew 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
146*3f1fc5f2SDavid Hunt 	if (index >= RTE_MAX_LCORE_FREQS)
147d26c18c9SAlan Carew 		freq = 0;
148d26c18c9SAlan Carew 	else
149d26c18c9SAlan Carew 		freq = global_core_freq_info[core_num].freqs[index];
150d26c18c9SAlan Carew 
151d26c18c9SAlan Carew 	return freq;
152d26c18c9SAlan Carew }
153d26c18c9SAlan Carew 
154d26c18c9SAlan Carew int
155d26c18c9SAlan Carew power_manager_exit(void)
156d26c18c9SAlan Carew {
157d26c18c9SAlan Carew 	unsigned int i;
158d26c18c9SAlan Carew 	int ret = 0;
1596453b928SDavid Hunt 	struct core_info *ci;
160c12ade20SDavid Hunt 	unsigned int max_core_num;
161d26c18c9SAlan Carew 
1626453b928SDavid Hunt 	ci = get_core_info();
1636453b928SDavid Hunt 	if (!ci) {
1646453b928SDavid Hunt 		RTE_LOG(ERR, POWER_MANAGER,
1656453b928SDavid Hunt 				"Failed to get core info!\n");
1666453b928SDavid Hunt 		return -1;
1676453b928SDavid Hunt 	}
1686453b928SDavid Hunt 
169751227a0SDavid Hunt 	if (ci->core_count > RTE_MAX_LCORE)
170751227a0SDavid Hunt 		max_core_num = RTE_MAX_LCORE;
171c12ade20SDavid Hunt 	else
172c12ade20SDavid Hunt 		max_core_num = ci->core_count;
173c12ade20SDavid Hunt 
174c12ade20SDavid Hunt 	for (i = 0; i < max_core_num; i++) {
1756453b928SDavid Hunt 		if (ci->cd[i].global_enabled_cpus) {
176d26c18c9SAlan Carew 			if (rte_power_exit(i) < 0) {
177d26c18c9SAlan Carew 				RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager "
178d26c18c9SAlan Carew 						"for core %u\n", i);
179d26c18c9SAlan Carew 				ret = -1;
180d26c18c9SAlan Carew 			}
1816453b928SDavid Hunt 			ci->cd[i].global_enabled_cpus = 0;
182d26c18c9SAlan Carew 		}
1836453b928SDavid Hunt 		remove_core_from_monitor(i);
1846453b928SDavid Hunt 	}
185d26c18c9SAlan Carew 	return ret;
186d26c18c9SAlan Carew }
187d26c18c9SAlan Carew 
188d26c18c9SAlan Carew int
189d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num)
190d26c18c9SAlan Carew {
191d26c18c9SAlan Carew 	int ret = 0;
192d26c18c9SAlan Carew 
193d26c18c9SAlan Carew 	POWER_SCALE_CORE(up, core_num, ret);
194d26c18c9SAlan Carew 	return ret;
195d26c18c9SAlan Carew }
196d26c18c9SAlan Carew 
197d26c18c9SAlan Carew int
198d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num)
199d26c18c9SAlan Carew {
200d26c18c9SAlan Carew 	int ret = 0;
201d26c18c9SAlan Carew 
202d26c18c9SAlan Carew 	POWER_SCALE_CORE(down, core_num, ret);
203d26c18c9SAlan Carew 	return ret;
204d26c18c9SAlan Carew }
205d26c18c9SAlan Carew 
206d26c18c9SAlan Carew int
207d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num)
208d26c18c9SAlan Carew {
209d26c18c9SAlan Carew 	int ret = 0;
210d26c18c9SAlan Carew 
211d26c18c9SAlan Carew 	POWER_SCALE_CORE(min, core_num, ret);
212d26c18c9SAlan Carew 	return ret;
213d26c18c9SAlan Carew }
214d26c18c9SAlan Carew 
215d26c18c9SAlan Carew int
216d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num)
217d26c18c9SAlan Carew {
218d26c18c9SAlan Carew 	int ret = 0;
219d26c18c9SAlan Carew 
220d26c18c9SAlan Carew 	POWER_SCALE_CORE(max, core_num, ret);
221d26c18c9SAlan Carew 	return ret;
222d26c18c9SAlan Carew }
223567997b9SDavid Hunt 
224567997b9SDavid Hunt int
225567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num)
226567997b9SDavid Hunt {
227567997b9SDavid Hunt 	int ret = 0;
228567997b9SDavid Hunt 
229567997b9SDavid Hunt 	POWER_SCALE_CORE(enable_turbo, core_num, ret);
230567997b9SDavid Hunt 	return ret;
231567997b9SDavid Hunt }
232567997b9SDavid Hunt 
233567997b9SDavid Hunt int
234567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num)
235567997b9SDavid Hunt {
236567997b9SDavid Hunt 	int ret = 0;
237567997b9SDavid Hunt 
238567997b9SDavid Hunt 	POWER_SCALE_CORE(disable_turbo, core_num, ret);
239567997b9SDavid Hunt 	return ret;
240567997b9SDavid Hunt }
2417f472f74SDavid Hunt 
2427f472f74SDavid Hunt int
2437f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num)
2447f472f74SDavid Hunt {
2457f472f74SDavid Hunt 	int ret = 0;
2466453b928SDavid Hunt 	struct core_info *ci;
2477f472f74SDavid Hunt 
2486453b928SDavid Hunt 	ci = get_core_info();
249751227a0SDavid Hunt 	if (core_num >= RTE_MAX_LCORE)
2507f472f74SDavid Hunt 		return -1;
2516453b928SDavid Hunt 	if (!(ci->cd[core_num].global_enabled_cpus))
2527f472f74SDavid Hunt 		return -1;
2537f472f74SDavid Hunt 	rte_spinlock_lock(&global_core_freq_info[core_num].power_sl);
2547f472f74SDavid Hunt 	ret = rte_power_set_freq(core_num,
2557f472f74SDavid Hunt 				global_core_freq_info[core_num].num_freqs / 2);
2567f472f74SDavid Hunt 	rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl);
2577f472f74SDavid Hunt 	return ret;
2587f472f74SDavid Hunt }
259