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