Branch data Line data Source code
1 : : /* SPDX-License-Identifier: BSD-3-Clause
2 : : * Copyright(c) 2010-2021 Intel Corporation
3 : : * Copyright(c) 2021 Arm Limited
4 : : * Copyright(c) 2023 Amd Limited
5 : : */
6 : :
7 : : #include <stdlib.h>
8 : :
9 : : #include <rte_memcpy.h>
10 : : #include <rte_stdatomic.h>
11 : :
12 : : #include "power_amd_pstate_cpufreq.h"
13 : : #include "power_common.h"
14 : :
15 : : /* macros used for rounding frequency to nearest 1000 */
16 : : #define FREQ_ROUNDING_DELTA 500
17 : : #define ROUND_FREQ_TO_N_1000 1000
18 : :
19 : : #define POWER_CONVERT_TO_DECIMAL 10
20 : :
21 : : #define POWER_GOVERNOR_USERSPACE "userspace"
22 : : #define POWER_SYSFILE_SETSPEED \
23 : : "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_setspeed"
24 : : #define POWER_SYSFILE_SCALING_MAX_FREQ \
25 : : "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_max_freq"
26 : : #define POWER_SYSFILE_SCALING_MIN_FREQ \
27 : : "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_min_freq"
28 : : #define POWER_SYSFILE_HIGHEST_PERF \
29 : : "/sys/devices/system/cpu/cpu%u/acpi_cppc/highest_perf"
30 : : #define POWER_SYSFILE_NOMINAL_PERF \
31 : : "/sys/devices/system/cpu/cpu%u/acpi_cppc/nominal_perf"
32 : : #define POWER_SYSFILE_NOMINAL_FREQ \
33 : : "/sys/devices/system/cpu/cpu%u/acpi_cppc/nominal_freq"
34 : :
35 : : #define POWER_AMD_PSTATE_DRIVER "amd-pstate"
36 : : #define BUS_FREQ 1000 /* khz */
37 : :
38 : : enum power_state {
39 : : POWER_IDLE = 0,
40 : : POWER_ONGOING,
41 : : POWER_USED,
42 : : POWER_UNKNOWN
43 : : };
44 : :
45 : : /**
46 : : * Power info per lcore.
47 : : */
48 : : struct amd_pstate_power_info {
49 : : uint32_t lcore_id; /**< Logical core id */
50 : : RTE_ATOMIC(uint32_t) state; /**< Power in use state */
51 : : FILE *f; /**< FD of scaling_setspeed */
52 : : char governor_ori[28]; /**< Original governor name */
53 : : uint32_t curr_idx; /**< Freq index in freqs array */
54 : : uint32_t nom_idx; /**< Nominal index in freqs array */
55 : : uint32_t highest_perf; /**< system wide max freq */
56 : : uint32_t nominal_perf; /**< system wide nominal freq */
57 : : uint16_t turbo_available; /**< Turbo Boost available */
58 : : uint16_t turbo_enable; /**< Turbo Boost enable/disable */
59 : : uint32_t nb_freqs; /**< number of available freqs */
60 : : uint32_t freqs[RTE_MAX_LCORE_FREQS]; /**< Frequency array */
61 : : } __rte_cache_aligned;
62 : :
63 : : static struct amd_pstate_power_info lcore_power_info[RTE_MAX_LCORE];
64 : :
65 : : /**
66 : : * It is to set specific freq for specific logical core, according to the index
67 : : * of supported frequencies.
68 : : */
69 : : static int
70 : 0 : set_freq_internal(struct amd_pstate_power_info *pi, uint32_t idx)
71 : : {
72 [ # # # # ]: 0 : if (idx >= RTE_MAX_LCORE_FREQS || idx >= pi->nb_freqs) {
73 : 0 : POWER_LOG(ERR, "Invalid frequency index %u, which "
74 : : "should be less than %u", idx, pi->nb_freqs);
75 : 0 : return -1;
76 : : }
77 : :
78 : : /* Check if it is the same as current */
79 [ # # ]: 0 : if (idx == pi->curr_idx)
80 : : return 0;
81 : :
82 : : POWER_DEBUG_LOG("Frequency[%u] %u to be set for lcore %u",
83 : : idx, pi->freqs[idx], pi->lcore_id);
84 [ # # ]: 0 : if (fseek(pi->f, 0, SEEK_SET) < 0) {
85 : 0 : POWER_LOG(ERR, "Fail to set file position indicator to 0 "
86 : : "for setting frequency for lcore %u", pi->lcore_id);
87 : 0 : return -1;
88 : : }
89 [ # # ]: 0 : if (fprintf(pi->f, "%u", pi->freqs[idx]) < 0) {
90 : 0 : POWER_LOG(ERR, "Fail to write new frequency for "
91 : : "lcore %u", pi->lcore_id);
92 : 0 : return -1;
93 : : }
94 : 0 : fflush(pi->f);
95 : 0 : pi->curr_idx = idx;
96 : :
97 : 0 : return 1;
98 : : }
99 : :
100 : : /**
101 : : * It is to check the current scaling governor by reading sys file, and then
102 : : * set it into 'userspace' if it is not by writing the sys file. The original
103 : : * governor will be saved for rolling back.
104 : : */
105 : : static int
106 : : power_set_governor_userspace(struct amd_pstate_power_info *pi)
107 : : {
108 : 1 : return power_set_governor(pi->lcore_id, POWER_GOVERNOR_USERSPACE,
109 : 1 : pi->governor_ori, sizeof(pi->governor_ori));
110 : : }
111 : :
112 : : static int
113 : 0 : power_check_turbo(struct amd_pstate_power_info *pi)
114 : : {
115 : 0 : FILE *f_nom = NULL, *f_max = NULL;
116 : : int ret = -1;
117 : 0 : uint32_t nominal_perf = 0, highest_perf = 0;
118 : :
119 : 0 : open_core_sysfs_file(&f_max, "r", POWER_SYSFILE_HIGHEST_PERF,
120 : : pi->lcore_id);
121 [ # # ]: 0 : if (f_max == NULL) {
122 : 0 : POWER_LOG(ERR, "failed to open %s",
123 : : POWER_SYSFILE_HIGHEST_PERF);
124 : 0 : goto err;
125 : : }
126 : :
127 : 0 : open_core_sysfs_file(&f_nom, "r", POWER_SYSFILE_NOMINAL_PERF,
128 : : pi->lcore_id);
129 [ # # ]: 0 : if (f_nom == NULL) {
130 : 0 : POWER_LOG(ERR, "failed to open %s",
131 : : POWER_SYSFILE_NOMINAL_PERF);
132 : 0 : goto err;
133 : : }
134 : :
135 : 0 : ret = read_core_sysfs_u32(f_max, &highest_perf);
136 [ # # ]: 0 : if (ret < 0) {
137 : 0 : POWER_LOG(ERR, "Failed to read %s",
138 : : POWER_SYSFILE_HIGHEST_PERF);
139 : 0 : goto err;
140 : : }
141 : :
142 : 0 : ret = read_core_sysfs_u32(f_nom, &nominal_perf);
143 [ # # ]: 0 : if (ret < 0) {
144 : 0 : POWER_LOG(ERR, "Failed to read %s",
145 : : POWER_SYSFILE_NOMINAL_PERF);
146 : 0 : goto err;
147 : : }
148 : :
149 : 0 : pi->highest_perf = highest_perf;
150 : 0 : pi->nominal_perf = nominal_perf;
151 : :
152 [ # # ]: 0 : if (highest_perf > nominal_perf) {
153 : 0 : pi->turbo_available = 1;
154 : 0 : pi->turbo_enable = 1;
155 : : ret = 0;
156 : : POWER_DEBUG_LOG("Lcore %u can do Turbo Boost! highest perf %u, "
157 : : "nominal perf %u",
158 : : pi->lcore_id, highest_perf, nominal_perf);
159 : : } else {
160 : 0 : pi->turbo_available = 0;
161 : 0 : pi->turbo_enable = 0;
162 : : POWER_DEBUG_LOG("Lcore %u Turbo not available! highest perf %u, "
163 : : "nominal perf %u",
164 : : pi->lcore_id, highest_perf, nominal_perf);
165 : : }
166 : :
167 : 0 : err:
168 [ # # ]: 0 : if (f_max != NULL)
169 : 0 : fclose(f_max);
170 [ # # ]: 0 : if (f_nom != NULL)
171 : 0 : fclose(f_nom);
172 : :
173 : 0 : return ret;
174 : : }
175 : :
176 : : /**
177 : : * It is to get the available frequencies of the specific lcore by reading the
178 : : * sys file.
179 : : */
180 : : static int
181 : 0 : power_get_available_freqs(struct amd_pstate_power_info *pi)
182 : : {
183 : 0 : FILE *f_min = NULL, *f_max = NULL, *f_nom = NULL;
184 : : int ret = -1, nominal_idx = -1;
185 : 0 : uint32_t scaling_min_freq = 0, scaling_max_freq = 0;
186 : : uint32_t i, num_freqs = RTE_MAX_LCORE_FREQS;
187 : 0 : uint32_t nominal_freq = 0, scaling_freq = 0;
188 : : uint32_t freq_calc = 0;
189 : :
190 : 0 : open_core_sysfs_file(&f_max, "r", POWER_SYSFILE_SCALING_MAX_FREQ,
191 : : pi->lcore_id);
192 [ # # ]: 0 : if (f_max == NULL) {
193 : 0 : POWER_LOG(ERR, "failed to open %s",
194 : : POWER_SYSFILE_SCALING_MAX_FREQ);
195 : 0 : goto out;
196 : : }
197 : :
198 : 0 : open_core_sysfs_file(&f_min, "r", POWER_SYSFILE_SCALING_MIN_FREQ,
199 : : pi->lcore_id);
200 [ # # ]: 0 : if (f_min == NULL) {
201 : 0 : POWER_LOG(ERR, "failed to open %s",
202 : : POWER_SYSFILE_SCALING_MIN_FREQ);
203 : 0 : goto out;
204 : : }
205 : :
206 : 0 : open_core_sysfs_file(&f_nom, "r", POWER_SYSFILE_NOMINAL_FREQ,
207 : : pi->lcore_id);
208 [ # # ]: 0 : if (f_nom == NULL) {
209 : 0 : POWER_LOG(ERR, "failed to open %s",
210 : : POWER_SYSFILE_NOMINAL_FREQ);
211 : 0 : goto out;
212 : : }
213 : :
214 : 0 : ret = read_core_sysfs_u32(f_max, &scaling_max_freq);
215 [ # # ]: 0 : if (ret < 0) {
216 : 0 : POWER_LOG(ERR, "Failed to read %s",
217 : : POWER_SYSFILE_SCALING_MAX_FREQ);
218 : 0 : goto out;
219 : : }
220 : :
221 : 0 : ret = read_core_sysfs_u32(f_min, &scaling_min_freq);
222 [ # # ]: 0 : if (ret < 0) {
223 : 0 : POWER_LOG(ERR, "Failed to read %s",
224 : : POWER_SYSFILE_SCALING_MIN_FREQ);
225 : 0 : goto out;
226 : : }
227 : :
228 : 0 : ret = read_core_sysfs_u32(f_nom, &nominal_freq);
229 [ # # ]: 0 : if (ret < 0) {
230 : 0 : POWER_LOG(ERR, "Failed to read %s",
231 : : POWER_SYSFILE_NOMINAL_FREQ);
232 : 0 : goto out;
233 : : }
234 : :
235 : 0 : power_check_turbo(pi);
236 : :
237 [ # # ]: 0 : if (scaling_max_freq < scaling_min_freq) {
238 : 0 : POWER_LOG(ERR, "scaling min freq exceeds max freq, "
239 : : "not expected! Check system power policy");
240 : 0 : goto out;
241 [ # # ]: 0 : } else if (scaling_max_freq == scaling_min_freq) {
242 : : num_freqs = 1;
243 : : }
244 : :
245 : : if (num_freqs > 1) {
246 : 0 : scaling_freq = (scaling_max_freq - scaling_min_freq);
247 : 0 : scaling_freq <<= 10;
248 : 0 : scaling_freq /= (num_freqs - 1);
249 : 0 : scaling_freq >>= 10;
250 : : } else {
251 : : scaling_freq = 0;
252 : : }
253 : :
254 : : /* Generate the freq bucket array. */
255 [ # # ]: 0 : for (i = 0, pi->nb_freqs = 0; i < num_freqs; i++) {
256 : 0 : freq_calc = scaling_max_freq - (i * scaling_freq);
257 : : /* convert the frequency to nearest 1000 value
258 : : * Ex: if freq=1396789 then freq_conv=1397000
259 : : * Ex: if freq=800030 then freq_conv=800000
260 : : */
261 : 0 : freq_calc = (freq_calc + FREQ_ROUNDING_DELTA)
262 : : / ROUND_FREQ_TO_N_1000;
263 : 0 : freq_calc = freq_calc * ROUND_FREQ_TO_N_1000;
264 : :
265 : : /* update the frequency table only if required */
266 [ # # ]: 0 : if ((pi->nb_freqs == 0) ||
267 [ # # ]: 0 : pi->freqs[pi->nb_freqs-1] != freq_calc) {
268 : 0 : pi->freqs[pi->nb_freqs++] = freq_calc;
269 : : }
270 [ # # ]: 0 : if (nominal_idx == -1) {
271 [ # # ]: 0 : if ((nominal_freq * BUS_FREQ) >= freq_calc) {
272 : 0 : pi->nom_idx = pi->nb_freqs - 1;
273 : 0 : nominal_idx = pi->nom_idx;
274 : : }
275 : : }
276 : : }
277 : :
278 : : ret = 0;
279 : :
280 : : POWER_DEBUG_LOG("%d frequency(s) of lcore %u are available",
281 : : num_freqs, pi->lcore_id);
282 : :
283 : 0 : out:
284 [ # # ]: 0 : if (f_min != NULL)
285 : 0 : fclose(f_min);
286 [ # # ]: 0 : if (f_max != NULL)
287 : 0 : fclose(f_max);
288 [ # # ]: 0 : if (f_nom != NULL)
289 : 0 : fclose(f_nom);
290 : :
291 : 0 : return ret;
292 : : }
293 : :
294 : : /**
295 : : * It is to fopen the sys file for the future setting the lcore frequency.
296 : : */
297 : : static int
298 : 0 : power_init_for_setting_freq(struct amd_pstate_power_info *pi)
299 : : {
300 : 0 : FILE *f = NULL;
301 : : char buf[BUFSIZ];
302 : : uint32_t i, freq;
303 : : int ret;
304 : :
305 : 0 : open_core_sysfs_file(&f, "rw+", POWER_SYSFILE_SETSPEED, pi->lcore_id);
306 [ # # ]: 0 : if (f == NULL) {
307 : 0 : POWER_LOG(ERR, "failed to open %s",
308 : : POWER_SYSFILE_SETSPEED);
309 : 0 : goto err;
310 : : }
311 : :
312 : 0 : ret = read_core_sysfs_s(f, buf, sizeof(buf));
313 [ # # ]: 0 : if (ret < 0) {
314 : 0 : POWER_LOG(ERR, "Failed to read %s",
315 : : POWER_SYSFILE_SETSPEED);
316 : 0 : goto err;
317 : : }
318 : :
319 : 0 : freq = strtoul(buf, NULL, POWER_CONVERT_TO_DECIMAL);
320 : :
321 : : /* convert the frequency to nearest 1000 value
322 : : * Ex: if freq=1396789 then freq_conv=1397000
323 : : * Ex: if freq=800030 then freq_conv=800000
324 : : */
325 : : unsigned int freq_conv = 0;
326 : 0 : freq_conv = (freq + FREQ_ROUNDING_DELTA)
327 : : / ROUND_FREQ_TO_N_1000;
328 : 0 : freq_conv = freq_conv * ROUND_FREQ_TO_N_1000;
329 : :
330 [ # # ]: 0 : for (i = 0; i < pi->nb_freqs; i++) {
331 [ # # ]: 0 : if (freq_conv == pi->freqs[i]) {
332 : 0 : pi->curr_idx = i;
333 : 0 : pi->f = f;
334 : 0 : return 0;
335 : : }
336 : : }
337 : :
338 : 0 : err:
339 [ # # ]: 0 : if (f != NULL)
340 : 0 : fclose(f);
341 : :
342 : : return -1;
343 : : }
344 : :
345 : : int
346 : 0 : power_amd_pstate_cpufreq_check_supported(void)
347 : : {
348 : 0 : return cpufreq_check_scaling_driver(POWER_AMD_PSTATE_DRIVER);
349 : : }
350 : :
351 : : int
352 : 1 : power_amd_pstate_cpufreq_init(unsigned int lcore_id)
353 : : {
354 : : struct amd_pstate_power_info *pi;
355 : : uint32_t exp_state;
356 : :
357 [ - + ]: 1 : if (lcore_id >= RTE_MAX_LCORE) {
358 : 0 : POWER_LOG(ERR, "Lcore id %u can not exceeds %u",
359 : : lcore_id, RTE_MAX_LCORE - 1U);
360 : 0 : return -1;
361 : : }
362 : :
363 : 1 : pi = &lcore_power_info[lcore_id];
364 : : exp_state = POWER_IDLE;
365 : : /* The power in use state works as a guard variable between
366 : : * the CPU frequency control initialization and exit process.
367 : : * The ACQUIRE memory ordering here pairs with the RELEASE
368 : : * ordering below as lock to make sure the frequency operations
369 : : * in the critical section are done under the correct state.
370 : : */
371 [ - + ]: 1 : if (!rte_atomic_compare_exchange_strong_explicit(&(pi->state),
372 : : &exp_state, POWER_ONGOING,
373 : : rte_memory_order_acquire, rte_memory_order_relaxed)) {
374 : 0 : POWER_LOG(INFO, "Power management of lcore %u is "
375 : : "in use", lcore_id);
376 : 0 : return -1;
377 : : }
378 : :
379 : 1 : pi->lcore_id = lcore_id;
380 : : /* Check and set the governor */
381 [ + - ]: 1 : if (power_set_governor_userspace(pi) < 0) {
382 : 1 : POWER_LOG(ERR, "Cannot set governor of lcore %u to "
383 : : "userspace", lcore_id);
384 : 1 : goto fail;
385 : : }
386 : :
387 : : /* Get the available frequencies */
388 [ # # ]: 0 : if (power_get_available_freqs(pi) < 0) {
389 : 0 : POWER_LOG(ERR, "Cannot get available frequencies of "
390 : : "lcore %u", lcore_id);
391 : 0 : goto fail;
392 : : }
393 : :
394 : : /* Init for setting lcore frequency */
395 [ # # ]: 0 : if (power_init_for_setting_freq(pi) < 0) {
396 : 0 : POWER_LOG(ERR, "Cannot init for setting frequency for "
397 : : "lcore %u", lcore_id);
398 : 0 : goto fail;
399 : : }
400 : :
401 : : /* Set freq to max by default */
402 [ # # ]: 0 : if (power_amd_pstate_cpufreq_freq_max(lcore_id) < 0) {
403 : 0 : POWER_LOG(ERR, "Cannot set frequency of lcore %u "
404 : : "to max", lcore_id);
405 : 0 : goto fail;
406 : : }
407 : :
408 : 0 : POWER_LOG(INFO, "Initialized successfully for lcore %u "
409 : : "power management", lcore_id);
410 : :
411 : 0 : rte_atomic_store_explicit(&(pi->state), POWER_USED, rte_memory_order_release);
412 : :
413 : 0 : return 0;
414 : :
415 : 1 : fail:
416 : 1 : rte_atomic_store_explicit(&(pi->state), POWER_UNKNOWN, rte_memory_order_release);
417 : 1 : return -1;
418 : : }
419 : :
420 : : /**
421 : : * It is to check the governor and then set the original governor back if
422 : : * needed by writing the sys file.
423 : : */
424 : : static int
425 : : power_set_governor_original(struct amd_pstate_power_info *pi)
426 : : {
427 : 0 : return power_set_governor(pi->lcore_id, pi->governor_ori, NULL, 0);
428 : : }
429 : :
430 : : int
431 : 0 : power_amd_pstate_cpufreq_exit(unsigned int lcore_id)
432 : : {
433 : : struct amd_pstate_power_info *pi;
434 : : uint32_t exp_state;
435 : :
436 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
437 : 0 : POWER_LOG(ERR, "Lcore id %u can not exceeds %u",
438 : : lcore_id, RTE_MAX_LCORE - 1U);
439 : 0 : return -1;
440 : : }
441 : : pi = &lcore_power_info[lcore_id];
442 : : exp_state = POWER_USED;
443 : : /* The power in use state works as a guard variable between
444 : : * the CPU frequency control initialization and exit process.
445 : : * The ACQUIRE memory ordering here pairs with the RELEASE
446 : : * ordering below as lock to make sure the frequency operations
447 : : * in the critical section are done under the correct state.
448 : : */
449 [ # # ]: 0 : if (!rte_atomic_compare_exchange_strong_explicit(&(pi->state),
450 : : &exp_state, POWER_ONGOING,
451 : : rte_memory_order_acquire, rte_memory_order_relaxed)) {
452 : 0 : POWER_LOG(INFO, "Power management of lcore %u is "
453 : : "not used", lcore_id);
454 : 0 : return -1;
455 : : }
456 : :
457 : : /* Close FD of setting freq */
458 : 0 : fclose(pi->f);
459 : 0 : pi->f = NULL;
460 : :
461 : : /* Set the governor back to the original */
462 [ # # ]: 0 : if (power_set_governor_original(pi) < 0) {
463 : 0 : POWER_LOG(ERR, "Cannot set the governor of %u back "
464 : : "to the original", lcore_id);
465 : 0 : goto fail;
466 : : }
467 : :
468 : 0 : POWER_LOG(INFO, "Power management of lcore %u has exited from "
469 : : "'userspace' mode and been set back to the "
470 : : "original", lcore_id);
471 : 0 : rte_atomic_store_explicit(&(pi->state), POWER_IDLE, rte_memory_order_release);
472 : :
473 : 0 : return 0;
474 : :
475 : : fail:
476 : 0 : rte_atomic_store_explicit(&(pi->state), POWER_UNKNOWN, rte_memory_order_release);
477 : :
478 : 0 : return -1;
479 : : }
480 : :
481 : : uint32_t
482 : 0 : power_amd_pstate_cpufreq_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t num)
483 : : {
484 : : struct amd_pstate_power_info *pi;
485 : :
486 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
487 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
488 : 0 : return 0;
489 : : }
490 : :
491 [ # # ]: 0 : if (freqs == NULL) {
492 : 0 : POWER_LOG(ERR, "NULL buffer supplied");
493 : 0 : return 0;
494 : : }
495 : :
496 : : pi = &lcore_power_info[lcore_id];
497 [ # # ]: 0 : if (num < pi->nb_freqs) {
498 : 0 : POWER_LOG(ERR, "Buffer size is not enough");
499 : 0 : return 0;
500 : : }
501 [ # # ]: 0 : rte_memcpy(freqs, pi->freqs, pi->nb_freqs * sizeof(uint32_t));
502 : :
503 : 0 : return pi->nb_freqs;
504 : : }
505 : :
506 : : uint32_t
507 : 0 : power_amd_pstate_cpufreq_get_freq(unsigned int lcore_id)
508 : : {
509 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
510 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
511 : 0 : return RTE_POWER_INVALID_FREQ_INDEX;
512 : : }
513 : :
514 : 0 : return lcore_power_info[lcore_id].curr_idx;
515 : : }
516 : :
517 : : int
518 : 0 : power_amd_pstate_cpufreq_set_freq(unsigned int lcore_id, uint32_t index)
519 : : {
520 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
521 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
522 : 0 : return -1;
523 : : }
524 : :
525 : 0 : return set_freq_internal(&(lcore_power_info[lcore_id]), index);
526 : : }
527 : :
528 : : int
529 : 0 : power_amd_pstate_cpufreq_freq_down(unsigned int lcore_id)
530 : : {
531 : : struct amd_pstate_power_info *pi;
532 : :
533 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
534 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
535 : 0 : return -1;
536 : : }
537 : :
538 : 0 : pi = &lcore_power_info[lcore_id];
539 [ # # ]: 0 : if (pi->curr_idx + 1 == pi->nb_freqs)
540 : : return 0;
541 : :
542 : : /* Frequencies in the array are from high to low. */
543 : 0 : return set_freq_internal(pi, pi->curr_idx + 1);
544 : : }
545 : :
546 : : int
547 : 0 : power_amd_pstate_cpufreq_freq_up(unsigned int lcore_id)
548 : : {
549 : : struct amd_pstate_power_info *pi;
550 : :
551 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
552 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
553 : 0 : return -1;
554 : : }
555 : :
556 : 0 : pi = &lcore_power_info[lcore_id];
557 [ # # # # ]: 0 : if (pi->curr_idx == 0 || (pi->curr_idx == pi->nom_idx &&
558 [ # # # # ]: 0 : pi->turbo_available && !pi->turbo_enable))
559 : : return 0;
560 : :
561 : : /* Frequencies in the array are from high to low. */
562 : 0 : return set_freq_internal(pi, pi->curr_idx - 1);
563 : : }
564 : :
565 : : int
566 : 0 : power_amd_pstate_cpufreq_freq_max(unsigned int lcore_id)
567 : : {
568 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
569 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
570 : 0 : return -1;
571 : : }
572 : :
573 : : /* Frequencies in the array are from high to low. */
574 [ # # ]: 0 : if (lcore_power_info[lcore_id].turbo_available) {
575 [ # # ]: 0 : if (lcore_power_info[lcore_id].turbo_enable)
576 : : /* Set to Turbo */
577 : 0 : return set_freq_internal(
578 : : &lcore_power_info[lcore_id], 0);
579 : : else
580 : : /* Set to max non-turbo */
581 : 0 : return set_freq_internal(
582 : : &lcore_power_info[lcore_id],
583 : : lcore_power_info[lcore_id].nom_idx);
584 : : } else
585 : 0 : return set_freq_internal(&lcore_power_info[lcore_id], 0);
586 : : }
587 : :
588 : : int
589 : 0 : power_amd_pstate_cpufreq_freq_min(unsigned int lcore_id)
590 : : {
591 : : struct amd_pstate_power_info *pi;
592 : :
593 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
594 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
595 : 0 : return -1;
596 : : }
597 : :
598 : 0 : pi = &lcore_power_info[lcore_id];
599 : :
600 : : /* Frequencies in the array are from high to low. */
601 : 0 : return set_freq_internal(pi, pi->nb_freqs - 1);
602 : : }
603 : :
604 : : int
605 : 0 : power_amd_pstate_turbo_status(unsigned int lcore_id)
606 : : {
607 : : struct amd_pstate_power_info *pi;
608 : :
609 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
610 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
611 : 0 : return -1;
612 : : }
613 : :
614 : : pi = &lcore_power_info[lcore_id];
615 : :
616 : 0 : return pi->turbo_enable;
617 : : }
618 : :
619 : : int
620 : 0 : power_amd_pstate_enable_turbo(unsigned int lcore_id)
621 : : {
622 : : struct amd_pstate_power_info *pi;
623 : :
624 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
625 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
626 : 0 : return -1;
627 : : }
628 : :
629 : : pi = &lcore_power_info[lcore_id];
630 : :
631 [ # # ]: 0 : if (pi->turbo_available)
632 : 0 : pi->turbo_enable = 1;
633 : : else {
634 : 0 : pi->turbo_enable = 0;
635 : 0 : POWER_LOG(ERR,
636 : : "Failed to enable turbo on lcore %u",
637 : : lcore_id);
638 : 0 : return -1;
639 : : }
640 : :
641 : : /* TODO: must set to max once enabling Turbo? Considering add condition:
642 : : * if ((pi->turbo_available) && (pi->curr_idx <= 1))
643 : : */
644 : : /* Max may have changed, so call to max function */
645 [ # # ]: 0 : if (power_amd_pstate_cpufreq_freq_max(lcore_id) < 0) {
646 : 0 : POWER_LOG(ERR,
647 : : "Failed to set frequency of lcore %u to max",
648 : : lcore_id);
649 : 0 : return -1;
650 : : }
651 : :
652 : : return 0;
653 : : }
654 : :
655 : : int
656 : 0 : power_amd_pstate_disable_turbo(unsigned int lcore_id)
657 : : {
658 : : struct amd_pstate_power_info *pi;
659 : :
660 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
661 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
662 : 0 : return -1;
663 : : }
664 : :
665 : : pi = &lcore_power_info[lcore_id];
666 : :
667 : 0 : pi->turbo_enable = 0;
668 : :
669 [ # # # # ]: 0 : if ((pi->turbo_available) && (pi->curr_idx <= pi->nom_idx)) {
670 : : /* Try to set freq to max by default coming out of turbo */
671 [ # # ]: 0 : if (power_amd_pstate_cpufreq_freq_max(lcore_id) < 0) {
672 : 0 : POWER_LOG(ERR,
673 : : "Failed to set frequency of lcore %u to max",
674 : : lcore_id);
675 : 0 : return -1;
676 : : }
677 : : }
678 : :
679 : : return 0;
680 : : }
681 : :
682 : : int
683 : 0 : power_amd_pstate_get_capabilities(unsigned int lcore_id,
684 : : struct rte_power_core_capabilities *caps)
685 : : {
686 : : struct amd_pstate_power_info *pi;
687 : :
688 [ # # ]: 0 : if (lcore_id >= RTE_MAX_LCORE) {
689 : 0 : POWER_LOG(ERR, "Invalid lcore ID");
690 : 0 : return -1;
691 : : }
692 [ # # ]: 0 : if (caps == NULL) {
693 : 0 : POWER_LOG(ERR, "Invalid argument");
694 : 0 : return -1;
695 : : }
696 : :
697 : : pi = &lcore_power_info[lcore_id];
698 : 0 : caps->capabilities = 0;
699 : 0 : caps->turbo = !!(pi->turbo_available);
700 : :
701 : 0 : return 0;
702 : : }
|