Branch data 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 : 40 : _get_core_avail_freqs(uint32_t lcore_id, uint32_t *freqs, uint32_t num)
24 : : {
25 : : uint32_t rc;
26 : :
27 [ # # # # ]: 40 : rc = rte_power_freqs(lcore_id, freqs, num);
28 [ - + ]: 40 : 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 : 40 : return rc;
35 : 0 : }
36 : :
37 : : static uint32_t
38 : 168 : _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 [ # # # # ]: 168 : rc = rte_power_freqs(lcore_id, freqs, SPDK_MAX_LCORE_FREQS);
45 [ - + ]: 168 : 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 [ # # # # ]: 168 : freq_index = rte_power_get_freq(lcore_id);
51 [ - + ]: 168 : 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 [ # # # # : 168 : return freqs[freq_index];
# # ]
58 : 0 : }
59 : :
60 : : static int
61 : 3 : _core_freq_up(uint32_t lcore_id)
62 : : {
63 [ # # # # ]: 3 : return rte_power_freq_up(lcore_id);
64 : : }
65 : :
66 : : static int
67 : 69 : _core_freq_down(uint32_t lcore_id)
68 : : {
69 [ # # # # ]: 69 : return rte_power_freq_down(lcore_id);
70 : : }
71 : :
72 : : static int
73 : 168 : _set_core_freq_max(uint32_t lcore_id)
74 : : {
75 [ # # # # ]: 168 : return rte_power_freq_max(lcore_id);
76 : : }
77 : :
78 : : static int
79 : 720 : _set_core_freq_min(uint32_t lcore_id)
80 : : {
81 [ # # # # ]: 720 : return rte_power_freq_min(lcore_id);
82 : : }
83 : :
84 : : static int
85 : 16 : _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 [ # # # # ]: 16 : rc = rte_power_get_capabilities(lcore_id, &caps);
91 [ - + ]: 16 : if (rc != 0) {
92 : 0 : return rc;
93 : : }
94 : :
95 [ # # # # ]: 16 : capabilities->priority = caps.priority == 0 ? false : true;
96 : :
97 : 16 : return 0;
98 : 0 : }
99 : :
100 : : static int
101 : 5 : _dump_info_json(struct spdk_json_write_ctx *w)
102 : : {
103 : : enum power_management_env env;
104 : :
105 : 5 : env = rte_power_get_env();
106 : :
107 [ - + ]: 5 : if (env == PM_ENV_ACPI_CPUFREQ) {
108 : 0 : spdk_json_write_named_string(w, "env", "acpi-cpufreq");
109 [ - + ]: 5 : } else if (env == PM_ENV_KVM_VM) {
110 : 0 : spdk_json_write_named_string(w, "env", "kvm");
111 [ + - ]: 5 : } else if (env == PM_ENV_PSTATE_CPUFREQ) {
112 : 5 : 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 [ # # ]: 0 : } else if (env == PM_ENV_AMD_PSTATE_CPUFREQ) {
117 : 0 : spdk_json_write_named_string(w, "env", "amd-pstate");
118 : : #endif
119 : 0 : } else {
120 : 0 : spdk_json_write_named_string(w, "env", "unknown");
121 : 0 : return -EINVAL;
122 : : }
123 : :
124 : 5 : return 0;
125 : 0 : }
126 : :
127 : : static int
128 : 85 : _init_core(uint32_t lcore_id)
129 : : {
130 : 6 : struct rte_power_core_capabilities caps;
131 : : int rc;
132 : :
133 : 85 : rc = rte_power_init(lcore_id);
134 [ + + ]: 85 : if (rc != 0) {
135 : 13 : SPDK_ERRLOG("Failed to initialize on core%d\n", lcore_id);
136 : 13 : return rc;
137 : : }
138 : :
139 [ # # # # ]: 72 : rc = rte_power_get_capabilities(lcore_id, &caps);
140 [ - + ]: 72 : if (rc != 0) {
141 : 0 : SPDK_ERRLOG("Failed retrieve capabilities of core%d\n", lcore_id);
142 : 0 : return rc;
143 : : }
144 : :
145 [ + - ]: 72 : if (caps.turbo) {
146 [ # # # # ]: 72 : rc = rte_power_freq_enable_turbo(lcore_id);
147 [ - + ]: 72 : if (rc != 0) {
148 : 0 : SPDK_ERRLOG("Failed to set turbo on core%d\n", lcore_id);
149 : 0 : return rc;
150 : : }
151 : 0 : }
152 : :
153 : 72 : return rc;
154 : 0 : }
155 : :
156 : : static int
157 : 30 : _init(void)
158 : : {
159 : 9 : struct spdk_cpuset smt_mask, app_mask;
160 : : uint32_t i, j;
161 : 30 : int rc = 0;
162 : :
163 [ - + ]: 30 : 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 : 30 : spdk_env_get_cpuset(&app_mask);
176 : 30 : spdk_cpuset_and(&app_mask, &smt_mask);
177 [ + + ]: 30 : if (!spdk_cpuset_equal(&app_mask, &smt_mask)) {
178 : 8 : SPDK_ERRLOG("App core mask contains some but not all of a set of SMT siblings\n");
179 : 8 : return -1;
180 : : }
181 : :
182 : : #if RTE_VERSION >= RTE_VERSION_NUM(23, 11, 0, 0)
183 [ + + ]: 105 : for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_AMD_PSTATE_CPUFREQ; i++) {
184 : : #else
185 : : for (i = PM_ENV_ACPI_CPUFREQ; i <= PM_ENV_CPPC_CPUFREQ; i++) {
186 : : #endif
187 [ + + ]: 92 : if (rte_power_check_env_supported(i) == 1) {
188 : 9 : rte_power_set_env(i);
189 : 9 : break;
190 : : }
191 : 0 : }
192 : :
193 [ + + ]: 94 : SPDK_ENV_FOREACH_CORE(i) {
194 : 85 : rc = _init_core(i);
195 [ + + ]: 85 : if (rc != 0) {
196 : 13 : SPDK_ERRLOG("Failed to initialize on core%d\n", i);
197 : 13 : break;
198 : : }
199 : 0 : }
200 : :
201 [ + + ]: 22 : if (rc == 0) {
202 : 9 : return rc;
203 : : }
204 : :
205 : : /* When initialization of a core failed, deinitialize prior cores. */
206 [ + - ]: 13 : SPDK_ENV_FOREACH_CORE(j) {
207 [ + - ]: 13 : if (j >= i) {
208 : 13 : break;
209 : : }
210 [ # # ]: 0 : if (rte_power_exit(j) != 0) {
211 : 0 : SPDK_ERRLOG("Failed to deinitialize on core%d\n", j);
212 : 0 : }
213 : 0 : }
214 : 13 : rte_power_unset_env();
215 : 13 : return rc;
216 : 1 : }
217 : :
218 : : static void
219 : 9 : _deinit(void)
220 : : {
221 : : uint32_t i;
222 : :
223 [ + + ]: 81 : SPDK_ENV_FOREACH_CORE(i) {
224 [ - + ]: 72 : if (rte_power_exit(i) != 0) {
225 : 0 : SPDK_ERRLOG("Failed to deinitialize on core%d\n", i);
226 : 0 : }
227 : 0 : }
228 : 9 : rte_power_unset_env();
229 : 9 : }
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 : 2100 : SPDK_GOVERNOR_REGISTER(dpdk_governor);
|