xref: /dpdk/lib/power/rte_power_uncore.c (revision ebe99d351a3f79acf305b882052f286c65cd9b25)
1 /* SPDX-License-Identifier: BSD-3-Clause
2  * Copyright(c) 2010-2014 Intel Corporation
3  * Copyright(c) 2023 AMD Corporation
4  */
5 
6 #include <rte_spinlock.h>
7 #include <rte_debug.h>
8 
9 #include "rte_power_uncore.h"
10 #include "power_common.h"
11 
12 static enum rte_uncore_power_mgmt_env global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
13 static struct rte_power_uncore_ops *global_uncore_ops;
14 
15 static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER;
16 static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list =
17 			TAILQ_HEAD_INITIALIZER(uncore_ops_list);
18 
19 const char *uncore_env_str[] = {
20 	"not set",
21 	"auto-detect",
22 	"intel-uncore",
23 	"amd-hsmp"
24 };
25 
26 /* register the ops struct in rte_power_uncore_ops, return 0 on success. */
27 int
28 rte_power_register_uncore_ops(struct rte_power_uncore_ops *driver_ops)
29 {
30 	if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs ||
31 			!driver_ops->get_num_dies || !driver_ops->get_num_freqs ||
32 			!driver_ops->get_avail_freqs || !driver_ops->get_freq ||
33 			!driver_ops->set_freq || !driver_ops->freq_max ||
34 			!driver_ops->freq_min) {
35 		POWER_LOG(ERR, "Missing callbacks while registering power ops");
36 		return -1;
37 	}
38 
39 	if (driver_ops->cb)
40 		driver_ops->cb();
41 
42 	TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next);
43 
44 	return 0;
45 }
46 
47 int
48 rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env)
49 {
50 	int ret = -1;
51 	struct rte_power_uncore_ops *ops;
52 
53 	rte_spinlock_lock(&global_env_cfg_lock);
54 
55 	if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) {
56 		POWER_LOG(ERR, "Uncore Power Management Env already set.");
57 		goto out;
58 	}
59 
60 	if (env == RTE_UNCORE_PM_ENV_AUTO_DETECT)
61 		/* Currently only intel_uncore is supported.
62 		 * This will be extended with auto-detection support
63 		 * for multiple uncore implementations.
64 		 */
65 		env = RTE_UNCORE_PM_ENV_INTEL_UNCORE;
66 
67 	if (env <= RTE_DIM(uncore_env_str)) {
68 		RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
69 			if (strncmp(ops->name, uncore_env_str[env],
70 				RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
71 				global_uncore_env = env;
72 				global_uncore_ops = ops;
73 				ret = 0;
74 				goto out;
75 			}
76 		POWER_LOG(ERR, "Power Management (%s) not supported",
77 				uncore_env_str[env]);
78 	} else
79 		POWER_LOG(ERR, "Invalid Power Management Environment");
80 
81 out:
82 	rte_spinlock_unlock(&global_env_cfg_lock);
83 	return ret;
84 }
85 
86 void
87 rte_power_unset_uncore_env(void)
88 {
89 	rte_spinlock_lock(&global_env_cfg_lock);
90 	global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET;
91 	rte_spinlock_unlock(&global_env_cfg_lock);
92 }
93 
94 enum rte_uncore_power_mgmt_env
95 rte_power_get_uncore_env(void)
96 {
97 	return global_uncore_env;
98 }
99 
100 int
101 rte_power_uncore_init(unsigned int pkg, unsigned int die)
102 {
103 	int ret = -1;
104 	struct rte_power_uncore_ops *ops;
105 	uint8_t env;
106 
107 	if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) &&
108 		(global_uncore_env != RTE_UNCORE_PM_ENV_AUTO_DETECT))
109 		return global_uncore_ops->init(pkg, die);
110 
111 	/* Auto Detect Environment */
112 	RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next)
113 		if (ops) {
114 			POWER_LOG(INFO,
115 				"Attempting to initialise %s power management...",
116 				ops->name);
117 			ret = ops->init(pkg, die);
118 			if (ret == 0) {
119 				for (env = 0; env < RTE_DIM(uncore_env_str); env++)
120 					if (strncmp(ops->name, uncore_env_str[env],
121 						RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) {
122 						rte_power_set_uncore_env(env);
123 						goto out;
124 					}
125 			}
126 		}
127 out:
128 	return ret;
129 }
130 
131 int
132 rte_power_uncore_exit(unsigned int pkg, unsigned int die)
133 {
134 	if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) &&
135 			global_uncore_ops)
136 		return global_uncore_ops->exit(pkg, die);
137 
138 	POWER_LOG(ERR,
139 		"Uncore Env has not been set, unable to exit gracefully");
140 
141 	return -1;
142 }
143 
144 uint32_t
145 rte_power_get_uncore_freq(unsigned int pkg, unsigned int die)
146 {
147 	RTE_ASSERT(global_uncore_ops != NULL);
148 	return global_uncore_ops->get_freq(pkg, die);
149 }
150 
151 int
152 rte_power_set_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index)
153 {
154 	RTE_ASSERT(global_uncore_ops != NULL);
155 	return global_uncore_ops->set_freq(pkg, die, index);
156 }
157 
158 int
159 rte_power_uncore_freq_max(unsigned int pkg, unsigned int die)
160 {
161 	RTE_ASSERT(global_uncore_ops != NULL);
162 	return global_uncore_ops->freq_max(pkg, die);
163 }
164 
165 int
166 rte_power_uncore_freq_min(unsigned int pkg, unsigned int die)
167 {
168 	RTE_ASSERT(global_uncore_ops != NULL);
169 	return global_uncore_ops->freq_min(pkg, die);
170 }
171 
172 int
173 rte_power_uncore_freqs(unsigned int pkg, unsigned int die,
174 			uint32_t *freqs, uint32_t num)
175 {
176 	RTE_ASSERT(global_uncore_ops != NULL);
177 	return global_uncore_ops->get_avail_freqs(pkg, die, freqs, num);
178 }
179 
180 int
181 rte_power_uncore_get_num_freqs(unsigned int pkg, unsigned int die)
182 {
183 	RTE_ASSERT(global_uncore_ops != NULL);
184 	return global_uncore_ops->get_num_freqs(pkg, die);
185 }
186 
187 unsigned int
188 rte_power_uncore_get_num_pkgs(void)
189 {
190 	RTE_ASSERT(global_uncore_ops != NULL);
191 	return global_uncore_ops->get_num_pkgs();
192 }
193 
194 unsigned int
195 rte_power_uncore_get_num_dies(unsigned int pkg)
196 {
197 	RTE_ASSERT(global_uncore_ops != NULL);
198 	return global_uncore_ops->get_num_dies(pkg);
199 }
200