xref: /spdk/module/scheduler/dpdk_governor/dpdk_governor.c (revision 3daf1f00f4be14d9cd35c5c4c41093a62c0dfab8)
1 /*   SPDX-License-Identifier: BSD-3-Clause
2  *   Copyright (C) 2020 Intel Corporation.
3  *   All rights reserved.
4  */
5 
6 #include "spdk/stdinc.h"
7 #include "spdk/log.h"
8 #include "spdk/env.h"
9 #include "spdk/event.h"
10 #include "spdk/scheduler.h"
11 
12 #include "spdk_internal/event.h"
13 
14 #include <rte_power.h>
15 #include <rte_version.h>
16 
17 static uint32_t
18 _get_core_avail_freqs(uint32_t lcore_id, uint32_t *freqs, uint32_t num)
19 {
20 	uint32_t rc;
21 
22 	rc = rte_power_freqs(lcore_id, freqs, num);
23 	if (!rc) {
24 		SPDK_ERRLOG("Unable to get current core frequency array for core %d\n.", lcore_id);
25 
26 		return 0;
27 	}
28 
29 	return rc;
30 }
31 
32 static uint32_t
33 _get_core_curr_freq(uint32_t lcore_id)
34 {
35 	uint32_t freqs[SPDK_MAX_LCORE_FREQS];
36 	uint32_t freq_index;
37 	int rc;
38 
39 	rc = rte_power_freqs(lcore_id, freqs, SPDK_MAX_LCORE_FREQS);
40 	if (!rc) {
41 		SPDK_ERRLOG("Unable to get current core frequency array for core %d\n.", lcore_id);
42 
43 		return 0;
44 	}
45 	freq_index = rte_power_get_freq(lcore_id);
46 	if (freq_index >= SPDK_MAX_LCORE_FREQS) {
47 		SPDK_ERRLOG("Unable to get current core frequency for core %d\n.", lcore_id);
48 
49 		return 0;
50 	}
51 
52 	return freqs[freq_index];
53 }
54 
55 static int
56 _core_freq_up(uint32_t lcore_id)
57 {
58 	return rte_power_freq_up(lcore_id);
59 }
60 
61 static int
62 _core_freq_down(uint32_t lcore_id)
63 {
64 	return rte_power_freq_down(lcore_id);
65 }
66 
67 static int
68 _set_core_freq_max(uint32_t lcore_id)
69 {
70 	return rte_power_freq_max(lcore_id);
71 }
72 
73 static int
74 _set_core_freq_min(uint32_t lcore_id)
75 {
76 	return rte_power_freq_min(lcore_id);
77 }
78 
79 static int
80 _get_core_capabilities(uint32_t lcore_id, struct spdk_governor_capabilities *capabilities)
81 {
82 	struct rte_power_core_capabilities caps;
83 	int rc;
84 
85 	rc = rte_power_get_capabilities(lcore_id, &caps);
86 	if (rc != 0) {
87 		return rc;
88 	}
89 
90 	capabilities->priority = caps.priority == 0 ? false : true;
91 
92 	return 0;
93 }
94 
95 static int
96 _dump_info_json(struct spdk_json_write_ctx *w)
97 {
98 	enum power_management_env env;
99 
100 	env = rte_power_get_env();
101 
102 	if (env == PM_ENV_ACPI_CPUFREQ) {
103 		spdk_json_write_named_string(w, "env", "acpi-cpufreq");
104 	} else if (env == PM_ENV_KVM_VM) {
105 		spdk_json_write_named_string(w, "env", "kvm");
106 	} else if (env == PM_ENV_PSTATE_CPUFREQ) {
107 		spdk_json_write_named_string(w, "env", "intel-pstate");
108 	} else if (env == PM_ENV_CPPC_CPUFREQ) {
109 		spdk_json_write_named_string(w, "env", "cppc-cpufreq");
110 #if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0)
111 	} else if (env == PM_ENV_AMD_PSTATE_CPUFREQ) {
112 		spdk_json_write_named_string(w, "env", "amd-pstate");
113 #endif
114 	} else {
115 		spdk_json_write_named_string(w, "env", "unknown");
116 		return -EINVAL;
117 	}
118 
119 	return 0;
120 }
121 
122 static int
123 _init_core(uint32_t lcore_id)
124 {
125 	struct rte_power_core_capabilities caps;
126 	int rc;
127 
128 	rc = rte_power_init(lcore_id);
129 	if (rc != 0) {
130 		SPDK_ERRLOG("Failed to initialize on core%d\n", lcore_id);
131 		return rc;
132 	}
133 
134 	rc = rte_power_get_capabilities(lcore_id, &caps);
135 	if (rc != 0) {
136 		SPDK_ERRLOG("Failed retrieve capabilities of core%d\n", lcore_id);
137 		return rc;
138 	}
139 
140 	if (caps.turbo) {
141 		rc = rte_power_freq_enable_turbo(lcore_id);
142 		if (rc != 0) {
143 			SPDK_ERRLOG("Failed to set turbo on core%d\n", lcore_id);
144 			return rc;
145 		}
146 	}
147 
148 	return rc;
149 }
150 
151 static int
152 _init(void)
153 {
154 	uint32_t i, j;
155 	int rc = 0;
156 
157 #if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0)
158 	for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_AMD_PSTATE_CPUFREQ; i++) {
159 #else
160 	for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_CPPC_CPUFREQ; i++) {
161 #endif
162 		if (rte_power_check_env_supported(i) == 1) {
163 			rte_power_set_env(i);
164 			break;
165 		}
166 	}
167 
168 	SPDK_ENV_FOREACH_CORE(i) {
169 		rc = _init_core(i);
170 		if (rc != 0) {
171 			SPDK_ERRLOG("Failed to initialize on core%d\n", i);
172 			break;
173 		}
174 	}
175 
176 	if (rc == 0) {
177 		return rc;
178 	}
179 
180 	/* When initialization of a core failed, deinitialize prior cores. */
181 	SPDK_ENV_FOREACH_CORE(j) {
182 		if (j >= i) {
183 			break;
184 		}
185 		if (rte_power_exit(j) != 0) {
186 			SPDK_ERRLOG("Failed to deinitialize on core%d\n", j);
187 		}
188 	}
189 	rte_power_unset_env();
190 	return rc;
191 }
192 
193 static void
194 _deinit(void)
195 {
196 	uint32_t i;
197 
198 	SPDK_ENV_FOREACH_CORE(i) {
199 		if (rte_power_exit(i) != 0) {
200 			SPDK_ERRLOG("Failed to deinitialize on core%d\n", i);
201 		}
202 	}
203 	rte_power_unset_env();
204 }
205 
206 static struct spdk_governor dpdk_governor = {
207 	.name = "dpdk_governor",
208 	.get_core_avail_freqs = _get_core_avail_freqs,
209 	.get_core_curr_freq = _get_core_curr_freq,
210 	.core_freq_up = _core_freq_up,
211 	.core_freq_down = _core_freq_down,
212 	.set_core_freq_max = _set_core_freq_max,
213 	.set_core_freq_min = _set_core_freq_min,
214 	.get_core_capabilities = _get_core_capabilities,
215 	.dump_info_json = _dump_info_json,
216 	.init = _init,
217 	.deinit = _deinit,
218 };
219 
220 SPDK_GOVERNOR_REGISTER(dpdk_governor);
221