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