Line data Source code
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_common.h>
15 : #include <rte_version.h>
16 : #if RTE_VERSION >= RTE_VERSION_NUM(24, 11, 0, 0)
17 : #include <rte_power_cpufreq.h>
18 : #else
19 : #include <rte_power.h>
20 : #endif
21 :
22 : static uint32_t
23 0 : _get_core_avail_freqs(uint32_t lcore_id, uint32_t *freqs, uint32_t num)
24 : {
25 : uint32_t rc;
26 :
27 0 : rc = rte_power_freqs(lcore_id, freqs, num);
28 0 : if (!rc) {
29 0 : SPDK_ERRLOG("Unable to get current core frequency array for core %d\n.", lcore_id);
30 :
31 0 : return 0;
32 : }
33 :
34 0 : return rc;
35 : }
36 :
37 : static uint32_t
38 0 : _get_core_curr_freq(uint32_t lcore_id)
39 : {
40 0 : uint32_t freqs[SPDK_MAX_LCORE_FREQS];
41 : uint32_t freq_index;
42 : int rc;
43 :
44 0 : rc = rte_power_freqs(lcore_id, freqs, SPDK_MAX_LCORE_FREQS);
45 0 : if (!rc) {
46 0 : SPDK_ERRLOG("Unable to get current core frequency array for core %d\n.", lcore_id);
47 :
48 0 : return 0;
49 : }
50 0 : freq_index = rte_power_get_freq(lcore_id);
51 0 : if (freq_index >= SPDK_MAX_LCORE_FREQS) {
52 0 : SPDK_ERRLOG("Unable to get current core frequency for core %d\n.", lcore_id);
53 :
54 0 : return 0;
55 : }
56 :
57 0 : return freqs[freq_index];
58 : }
59 :
60 : static int
61 0 : _core_freq_up(uint32_t lcore_id)
62 : {
63 0 : return rte_power_freq_up(lcore_id);
64 : }
65 :
66 : static int
67 0 : _core_freq_down(uint32_t lcore_id)
68 : {
69 0 : return rte_power_freq_down(lcore_id);
70 : }
71 :
72 : static int
73 0 : _set_core_freq_max(uint32_t lcore_id)
74 : {
75 0 : return rte_power_freq_max(lcore_id);
76 : }
77 :
78 : static int
79 0 : _set_core_freq_min(uint32_t lcore_id)
80 : {
81 0 : return rte_power_freq_min(lcore_id);
82 : }
83 :
84 : static int
85 0 : _get_core_capabilities(uint32_t lcore_id, struct spdk_governor_capabilities *capabilities)
86 : {
87 0 : struct rte_power_core_capabilities caps;
88 : int rc;
89 :
90 0 : rc = rte_power_get_capabilities(lcore_id, &caps);
91 0 : if (rc != 0) {
92 0 : return rc;
93 : }
94 :
95 0 : capabilities->priority = caps.priority == 0 ? false : true;
96 :
97 0 : return 0;
98 : }
99 :
100 : static int
101 0 : _dump_info_json(struct spdk_json_write_ctx *w)
102 : {
103 : enum power_management_env env;
104 :
105 0 : env = rte_power_get_env();
106 :
107 0 : if (env == PM_ENV_ACPI_CPUFREQ) {
108 0 : spdk_json_write_named_string(w, "env", "acpi-cpufreq");
109 0 : } else if (env == PM_ENV_KVM_VM) {
110 0 : spdk_json_write_named_string(w, "env", "kvm");
111 0 : } else if (env == PM_ENV_PSTATE_CPUFREQ) {
112 0 : spdk_json_write_named_string(w, "env", "intel-pstate");
113 0 : } else if (env == PM_ENV_CPPC_CPUFREQ) {
114 0 : spdk_json_write_named_string(w, "env", "cppc-cpufreq");
115 : #if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0)
116 : } else if (env == PM_ENV_AMD_PSTATE_CPUFREQ) {
117 : spdk_json_write_named_string(w, "env", "amd-pstate");
118 : #endif
119 : } else {
120 0 : spdk_json_write_named_string(w, "env", "unknown");
121 0 : return -EINVAL;
122 : }
123 :
124 0 : return 0;
125 : }
126 :
127 : static int
128 0 : _init_core(uint32_t lcore_id)
129 : {
130 0 : struct rte_power_core_capabilities caps;
131 : int rc;
132 :
133 0 : rc = rte_power_init(lcore_id);
134 0 : if (rc != 0) {
135 0 : SPDK_ERRLOG("Failed to initialize on core%d\n", lcore_id);
136 0 : return rc;
137 : }
138 :
139 0 : rc = rte_power_get_capabilities(lcore_id, &caps);
140 0 : if (rc != 0) {
141 0 : SPDK_ERRLOG("Failed retrieve capabilities of core%d\n", lcore_id);
142 0 : return rc;
143 : }
144 :
145 0 : if (caps.turbo) {
146 0 : rc = rte_power_freq_enable_turbo(lcore_id);
147 0 : if (rc != 0) {
148 0 : SPDK_ERRLOG("Failed to set turbo on core%d\n", lcore_id);
149 0 : return rc;
150 : }
151 : }
152 :
153 0 : return rc;
154 : }
155 :
156 : static int
157 0 : _init(void)
158 : {
159 0 : struct spdk_cpuset smt_mask, app_mask;
160 : uint32_t i, j;
161 0 : int rc = 0;
162 :
163 0 : if (!spdk_env_core_get_smt_cpuset(&smt_mask, UINT32_MAX)) {
164 : /* We could not get SMT status on this system, don't allow
165 : * the governor to load since we cannot guarantee we are running
166 : * on a subset of some SMT siblings.
167 : */
168 0 : SPDK_ERRLOG("Cannot detect SMT status\n");
169 0 : return -1;
170 : }
171 :
172 : /* Verify that if our app mask includes any SMT siblings, that it has
173 : * all of those siblings. Otherwise the governor cannot work.
174 : */
175 0 : spdk_env_get_cpuset(&app_mask);
176 0 : spdk_cpuset_and(&app_mask, &smt_mask);
177 0 : if (!spdk_cpuset_equal(&app_mask, &smt_mask)) {
178 0 : SPDK_ERRLOG("App core mask contains some but not all of a set of SMT siblings\n");
179 0 : return -1;
180 : }
181 :
182 : #if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0)
183 : for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_AMD_PSTATE_CPUFREQ; i++) {
184 : #else
185 0 : for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_CPPC_CPUFREQ; i++) {
186 : #endif
187 0 : if (rte_power_check_env_supported(i) == 1) {
188 0 : rte_power_set_env(i);
189 0 : break;
190 : }
191 : }
192 :
193 0 : SPDK_ENV_FOREACH_CORE(i) {
194 0 : rc = _init_core(i);
195 0 : if (rc != 0) {
196 0 : SPDK_ERRLOG("Failed to initialize on core%d\n", i);
197 0 : break;
198 : }
199 : }
200 :
201 0 : if (rc == 0) {
202 0 : return rc;
203 : }
204 :
205 : /* When initialization of a core failed, deinitialize prior cores. */
206 0 : SPDK_ENV_FOREACH_CORE(j) {
207 0 : if (j >= i) {
208 0 : break;
209 : }
210 0 : if (rte_power_exit(j) != 0) {
211 0 : SPDK_ERRLOG("Failed to deinitialize on core%d\n", j);
212 : }
213 : }
214 0 : rte_power_unset_env();
215 0 : return rc;
216 : }
217 :
218 : static void
219 0 : _deinit(void)
220 : {
221 : uint32_t i;
222 :
223 0 : SPDK_ENV_FOREACH_CORE(i) {
224 0 : if (rte_power_exit(i) != 0) {
225 0 : SPDK_ERRLOG("Failed to deinitialize on core%d\n", i);
226 : }
227 : }
228 0 : rte_power_unset_env();
229 0 : }
230 :
231 : static struct spdk_governor dpdk_governor = {
232 : .name = "dpdk_governor",
233 : .get_core_avail_freqs = _get_core_avail_freqs,
234 : .get_core_curr_freq = _get_core_curr_freq,
235 : .core_freq_up = _core_freq_up,
236 : .core_freq_down = _core_freq_down,
237 : .set_core_freq_max = _set_core_freq_max,
238 : .set_core_freq_min = _set_core_freq_min,
239 : .get_core_capabilities = _get_core_capabilities,
240 : .dump_info_json = _dump_info_json,
241 : .init = _init,
242 : .deinit = _deinit,
243 : };
244 :
245 0 : SPDK_GOVERNOR_REGISTER(dpdk_governor);
|