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