1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2018 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 #include <errno.h> 15 #include <inttypes.h> 16 17 #include <rte_memcpy.h> 18 #include <rte_memory.h> 19 #include <rte_string_fns.h> 20 21 #include "power_pstate_cpufreq.h" 22 #include "power_common.h" 23 24 /* macros used for rounding frequency to nearest 100000 */ 25 #define FREQ_ROUNDING_DELTA 50000 26 #define ROUND_FREQ_TO_N_100000 100000 27 28 #define BUS_FREQ 100000 29 30 #define POWER_GOVERNOR_PERF "performance" 31 #define POWER_SYSFILE_MAX_FREQ \ 32 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_max_freq" 33 #define POWER_SYSFILE_MIN_FREQ \ 34 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_min_freq" 35 #define POWER_SYSFILE_CUR_FREQ \ 36 "/sys/devices/system/cpu/cpu%u/cpufreq/scaling_cur_freq" 37 #define POWER_SYSFILE_BASE_MAX_FREQ \ 38 "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq" 39 #define POWER_SYSFILE_BASE_MIN_FREQ \ 40 "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_min_freq" 41 #define POWER_SYSFILE_BASE_FREQ \ 42 "/sys/devices/system/cpu/cpu%u/cpufreq/base_frequency" 43 #define POWER_PSTATE_DRIVER "intel_pstate" 44 #define POWER_MSR_PATH "/dev/cpu/%u/msr" 45 46 /* 47 * MSR related 48 */ 49 #define PLATFORM_INFO 0x0CE 50 #define NON_TURBO_MASK 0xFF00 51 #define NON_TURBO_OFFSET 0x8 52 53 54 enum power_state { 55 POWER_IDLE = 0, 56 POWER_ONGOING, 57 POWER_USED, 58 POWER_UNKNOWN 59 }; 60 61 struct pstate_power_info { 62 unsigned int lcore_id; /**< Logical core id */ 63 uint32_t freqs[RTE_MAX_LCORE_FREQS]; /**< Frequency array */ 64 uint32_t nb_freqs; /**< number of available freqs */ 65 FILE *f_cur_min; /**< FD of scaling_min */ 66 FILE *f_cur_max; /**< FD of scaling_max */ 67 char governor_ori[32]; /**< Original governor name */ 68 uint32_t curr_idx; /**< Freq index in freqs array */ 69 uint32_t non_turbo_max_ratio; /**< Non Turbo Max ratio */ 70 uint32_t sys_max_freq; /**< system wide max freq */ 71 uint32_t core_base_freq; /**< core base freq */ 72 uint32_t state; /**< Power in use state */ 73 uint16_t turbo_available; /**< Turbo Boost available */ 74 uint16_t turbo_enable; /**< Turbo Boost enable/disable */ 75 uint16_t priority_core; /**< High Performance core */ 76 } __rte_cache_aligned; 77 78 79 static struct pstate_power_info lcore_power_info[RTE_MAX_LCORE]; 80 81 /** 82 * It is to read the specific MSR. 83 */ 84 85 static int32_t 86 power_rdmsr(int msr, uint64_t *val, unsigned int lcore_id) 87 { 88 int fd, ret; 89 char fullpath[PATH_MAX]; 90 91 snprintf(fullpath, sizeof(fullpath), POWER_MSR_PATH, lcore_id); 92 93 fd = open(fullpath, O_RDONLY); 94 95 if (fd < 0) { 96 RTE_LOG(ERR, POWER, "Error opening '%s': %s\n", fullpath, 97 strerror(errno)); 98 return fd; 99 } 100 101 ret = pread(fd, val, sizeof(uint64_t), msr); 102 103 if (ret < 0) { 104 RTE_LOG(ERR, POWER, "Error reading '%s': %s\n", fullpath, 105 strerror(errno)); 106 goto out; 107 } 108 109 POWER_DEBUG_TRACE("MSR Path %s, offset 0x%X for lcore %u\n", 110 fullpath, msr, lcore_id); 111 112 POWER_DEBUG_TRACE("Ret value %d, content is 0x%"PRIx64"\n", ret, *val); 113 114 out: close(fd); 115 return ret; 116 } 117 118 /** 119 * It is to fopen the sys file for the future setting the lcore frequency. 120 */ 121 static int 122 power_init_for_setting_freq(struct pstate_power_info *pi) 123 { 124 FILE *f_base = NULL, *f_base_max = NULL, *f_min = NULL, *f_max = NULL; 125 uint32_t base_ratio, base_max_ratio; 126 uint64_t max_non_turbo; 127 int ret; 128 129 /* open all files we expect to have open */ 130 open_core_sysfs_file(&f_base_max, "r", POWER_SYSFILE_BASE_MAX_FREQ, 131 pi->lcore_id); 132 if (f_base_max == NULL) { 133 RTE_LOG(ERR, POWER, "failed to open %s\n", 134 POWER_SYSFILE_BASE_MAX_FREQ); 135 goto err; 136 } 137 138 open_core_sysfs_file(&f_min, "rw+", POWER_SYSFILE_MIN_FREQ, 139 pi->lcore_id); 140 if (f_min == NULL) { 141 RTE_LOG(ERR, POWER, "failed to open %s\n", 142 POWER_SYSFILE_MIN_FREQ); 143 goto err; 144 } 145 146 open_core_sysfs_file(&f_max, "rw+", POWER_SYSFILE_MAX_FREQ, 147 pi->lcore_id); 148 if (f_max == NULL) { 149 RTE_LOG(ERR, POWER, "failed to open %s\n", 150 POWER_SYSFILE_MAX_FREQ); 151 goto err; 152 } 153 154 open_core_sysfs_file(&f_base, "r", POWER_SYSFILE_BASE_FREQ, 155 pi->lcore_id); 156 /* base ratio file may not exist in some kernels, so no error check */ 157 158 /* read base max ratio */ 159 ret = read_core_sysfs_u32(f_base_max, &base_max_ratio); 160 if (ret < 0) { 161 RTE_LOG(ERR, POWER, "Failed to read %s\n", 162 POWER_SYSFILE_BASE_MAX_FREQ); 163 goto err; 164 } 165 166 /* base ratio may not exist */ 167 if (f_base != NULL) { 168 ret = read_core_sysfs_u32(f_base, &base_ratio); 169 if (ret < 0) { 170 RTE_LOG(ERR, POWER, "Failed to read %s\n", 171 POWER_SYSFILE_BASE_FREQ); 172 goto err; 173 } 174 } else { 175 base_ratio = 0; 176 } 177 178 /* Add MSR read to detect turbo status */ 179 if (power_rdmsr(PLATFORM_INFO, &max_non_turbo, pi->lcore_id) < 0) 180 goto err; 181 /* no errors after this point */ 182 183 /* convert ratios to bins */ 184 base_max_ratio /= BUS_FREQ; 185 base_ratio /= BUS_FREQ; 186 187 /* assign file handles */ 188 pi->f_cur_min = f_min; 189 pi->f_cur_max = f_max; 190 191 max_non_turbo = (max_non_turbo&NON_TURBO_MASK)>>NON_TURBO_OFFSET; 192 193 POWER_DEBUG_TRACE("no turbo perf %"PRIu64"\n", max_non_turbo); 194 195 pi->non_turbo_max_ratio = (uint32_t)max_non_turbo; 196 197 /* 198 * If base_frequency is reported as greater than the maximum 199 * turbo frequency, that's a known issue with some kernels. 200 * Set base_frequency to max_non_turbo as a workaround. 201 */ 202 if (base_ratio > base_max_ratio) { 203 /* base_ratio is greater than max turbo. Kernel bug. */ 204 pi->priority_core = 0; 205 goto out; 206 } 207 208 /* 209 * If base_frequency is reported as greater than the maximum 210 * non-turbo frequency, then mark it as a high priority core. 211 */ 212 if (base_ratio > max_non_turbo) 213 pi->priority_core = 1; 214 else 215 pi->priority_core = 0; 216 pi->core_base_freq = base_ratio * BUS_FREQ; 217 218 out: 219 if (f_base != NULL) 220 fclose(f_base); 221 fclose(f_base_max); 222 /* f_min and f_max are stored, no need to close */ 223 return 0; 224 225 err: 226 if (f_base != NULL) 227 fclose(f_base); 228 if (f_base_max != NULL) 229 fclose(f_base_max); 230 if (f_min != NULL) 231 fclose(f_min); 232 if (f_max != NULL) 233 fclose(f_max); 234 return -1; 235 } 236 237 static int 238 set_freq_internal(struct pstate_power_info *pi, uint32_t idx) 239 { 240 uint32_t target_freq = 0; 241 242 if (idx >= RTE_MAX_LCORE_FREQS || idx >= pi->nb_freqs) { 243 RTE_LOG(ERR, POWER, "Invalid frequency index %u, which " 244 "should be less than %u\n", idx, pi->nb_freqs); 245 return -1; 246 } 247 248 /* Check if it is the same as current */ 249 if (idx == pi->curr_idx) 250 return 0; 251 252 /* Because Intel Pstate Driver only allow user change min/max hint 253 * User need change the min/max as same value. 254 */ 255 if (fseek(pi->f_cur_min, 0, SEEK_SET) < 0) { 256 RTE_LOG(ERR, POWER, "Fail to set file position indicator to 0 " 257 "for setting frequency for lcore %u\n", 258 pi->lcore_id); 259 return -1; 260 } 261 262 if (fseek(pi->f_cur_max, 0, SEEK_SET) < 0) { 263 RTE_LOG(ERR, POWER, "Fail to set file position indicator to 0 " 264 "for setting frequency for lcore %u\n", 265 pi->lcore_id); 266 return -1; 267 } 268 269 /* Turbo is available and enabled, first freq bucket is sys max freq */ 270 if (pi->turbo_available && idx == 0) { 271 if (pi->turbo_enable) 272 target_freq = pi->sys_max_freq; 273 else { 274 RTE_LOG(ERR, POWER, "Turbo is off, frequency can't be scaled up more %u\n", 275 pi->lcore_id); 276 return -1; 277 } 278 } else 279 target_freq = pi->freqs[idx]; 280 281 /* Decrease freq, the min freq should be updated first */ 282 if (idx > pi->curr_idx) { 283 284 if (fprintf(pi->f_cur_min, "%u", target_freq) < 0) { 285 RTE_LOG(ERR, POWER, "Fail to write new frequency for " 286 "lcore %u\n", pi->lcore_id); 287 return -1; 288 } 289 290 if (fprintf(pi->f_cur_max, "%u", target_freq) < 0) { 291 RTE_LOG(ERR, POWER, "Fail to write new frequency for " 292 "lcore %u\n", pi->lcore_id); 293 return -1; 294 } 295 296 POWER_DEBUG_TRACE("Frequency '%u' to be set for lcore %u\n", 297 target_freq, pi->lcore_id); 298 299 fflush(pi->f_cur_min); 300 fflush(pi->f_cur_max); 301 302 } 303 304 /* Increase freq, the max freq should be updated first */ 305 if (idx < pi->curr_idx) { 306 307 if (fprintf(pi->f_cur_max, "%u", target_freq) < 0) { 308 RTE_LOG(ERR, POWER, "Fail to write new frequency for " 309 "lcore %u\n", pi->lcore_id); 310 return -1; 311 } 312 313 if (fprintf(pi->f_cur_min, "%u", target_freq) < 0) { 314 RTE_LOG(ERR, POWER, "Fail to write new frequency for " 315 "lcore %u\n", pi->lcore_id); 316 return -1; 317 } 318 319 POWER_DEBUG_TRACE("Frequency '%u' to be set for lcore %u\n", 320 target_freq, pi->lcore_id); 321 322 fflush(pi->f_cur_max); 323 fflush(pi->f_cur_min); 324 } 325 326 pi->curr_idx = idx; 327 328 return 1; 329 } 330 331 /** 332 * It is to check the current scaling governor by reading sys file, and then 333 * set it into 'performance' if it is not by writing the sys file. The original 334 * governor will be saved for rolling back. 335 */ 336 static int 337 power_set_governor_performance(struct pstate_power_info *pi) 338 { 339 return power_set_governor(pi->lcore_id, POWER_GOVERNOR_PERF, 340 pi->governor_ori, sizeof(pi->governor_ori)); 341 } 342 343 /** 344 * It is to check the governor and then set the original governor back if 345 * needed by writing the sys file. 346 */ 347 static int 348 power_set_governor_original(struct pstate_power_info *pi) 349 { 350 return power_set_governor(pi->lcore_id, pi->governor_ori, NULL, 0); 351 } 352 353 /** 354 * It is to get the available frequencies of the specific lcore by reading the 355 * sys file. 356 */ 357 static int 358 power_get_available_freqs(struct pstate_power_info *pi) 359 { 360 FILE *f_min = NULL, *f_max = NULL; 361 int ret = -1; 362 uint32_t sys_min_freq = 0, sys_max_freq = 0, base_max_freq = 0; 363 uint32_t i, num_freqs = 0; 364 365 /* open all files */ 366 open_core_sysfs_file(&f_max, "r", POWER_SYSFILE_BASE_MAX_FREQ, 367 pi->lcore_id); 368 if (f_max == NULL) { 369 RTE_LOG(ERR, POWER, "failed to open %s\n", 370 POWER_SYSFILE_BASE_MAX_FREQ); 371 goto out; 372 } 373 374 open_core_sysfs_file(&f_min, "r", POWER_SYSFILE_BASE_MIN_FREQ, 375 pi->lcore_id); 376 if (f_min == NULL) { 377 RTE_LOG(ERR, POWER, "failed to open %s\n", 378 POWER_SYSFILE_BASE_MIN_FREQ); 379 goto out; 380 } 381 382 /* read base ratios */ 383 ret = read_core_sysfs_u32(f_max, &sys_max_freq); 384 if (ret < 0) { 385 RTE_LOG(ERR, POWER, "Failed to read %s\n", 386 POWER_SYSFILE_BASE_MAX_FREQ); 387 goto out; 388 } 389 390 ret = read_core_sysfs_u32(f_min, &sys_min_freq); 391 if (ret < 0) { 392 RTE_LOG(ERR, POWER, "Failed to read %s\n", 393 POWER_SYSFILE_BASE_MIN_FREQ); 394 goto out; 395 } 396 397 if (sys_max_freq < sys_min_freq) 398 goto out; 399 400 pi->sys_max_freq = sys_max_freq; 401 402 if (pi->priority_core == 1) 403 base_max_freq = pi->core_base_freq; 404 else 405 base_max_freq = pi->non_turbo_max_ratio * BUS_FREQ; 406 407 POWER_DEBUG_TRACE("sys min %u, sys max %u, base_max %u\n", 408 sys_min_freq, 409 sys_max_freq, 410 base_max_freq); 411 412 if (base_max_freq < sys_max_freq) 413 pi->turbo_available = 1; 414 else 415 pi->turbo_available = 0; 416 417 /* If turbo is available then there is one extra freq bucket 418 * to store the sys max freq which value is base_max +1 419 */ 420 num_freqs = (base_max_freq - sys_min_freq) / BUS_FREQ + 1 + 421 pi->turbo_available; 422 if (num_freqs >= RTE_MAX_LCORE_FREQS) { 423 RTE_LOG(ERR, POWER, "Too many available frequencies: %d\n", 424 num_freqs); 425 goto out; 426 } 427 428 /* Generate the freq bucket array. 429 * If turbo is available the freq bucket[0] value is base_max +1 430 * the bucket[1] is base_max, bucket[2] is base_max - BUS_FREQ 431 * and so on. 432 * If turbo is not available bucket[0] is base_max and so on 433 */ 434 for (i = 0, pi->nb_freqs = 0; i < num_freqs; i++) { 435 if ((i == 0) && pi->turbo_available) 436 pi->freqs[pi->nb_freqs++] = base_max_freq + 1; 437 else 438 pi->freqs[pi->nb_freqs++] = 439 base_max_freq - (i - pi->turbo_available) * BUS_FREQ; 440 } 441 442 ret = 0; 443 444 POWER_DEBUG_TRACE("%d frequency(s) of lcore %u are available\n", 445 num_freqs, pi->lcore_id); 446 447 out: 448 if (f_min != NULL) 449 fclose(f_min); 450 if (f_max != NULL) 451 fclose(f_max); 452 453 return ret; 454 } 455 456 static int 457 power_get_cur_idx(struct pstate_power_info *pi) 458 { 459 FILE *f_cur; 460 int ret = -1; 461 uint32_t sys_cur_freq = 0; 462 unsigned int i; 463 464 open_core_sysfs_file(&f_cur, "r", POWER_SYSFILE_CUR_FREQ, 465 pi->lcore_id); 466 if (f_cur == NULL) { 467 RTE_LOG(ERR, POWER, "failed to open %s\n", 468 POWER_SYSFILE_CUR_FREQ); 469 goto fail; 470 } 471 472 ret = read_core_sysfs_u32(f_cur, &sys_cur_freq); 473 if (ret < 0) { 474 RTE_LOG(ERR, POWER, "Failed to read %s\n", 475 POWER_SYSFILE_CUR_FREQ); 476 goto fail; 477 } 478 479 /* convert the frequency to nearest 100000 value 480 * Ex: if sys_cur_freq=1396789 then freq_conv=1400000 481 * Ex: if sys_cur_freq=800030 then freq_conv=800000 482 * Ex: if sys_cur_freq=800030 then freq_conv=800000 483 */ 484 unsigned int freq_conv = 0; 485 freq_conv = (sys_cur_freq + FREQ_ROUNDING_DELTA) 486 / ROUND_FREQ_TO_N_100000; 487 freq_conv = freq_conv * ROUND_FREQ_TO_N_100000; 488 489 for (i = 0; i < pi->nb_freqs; i++) { 490 if (freq_conv == pi->freqs[i]) { 491 pi->curr_idx = i; 492 break; 493 } 494 } 495 496 ret = 0; 497 fail: 498 if (f_cur != NULL) 499 fclose(f_cur); 500 return ret; 501 } 502 503 int 504 power_pstate_cpufreq_check_supported(void) 505 { 506 return cpufreq_check_scaling_driver(POWER_PSTATE_DRIVER); 507 } 508 509 int 510 power_pstate_cpufreq_init(unsigned int lcore_id) 511 { 512 struct pstate_power_info *pi; 513 uint32_t exp_state; 514 515 if (lcore_id >= RTE_MAX_LCORE) { 516 RTE_LOG(ERR, POWER, "Lcore id %u can not exceed %u\n", 517 lcore_id, RTE_MAX_LCORE - 1U); 518 return -1; 519 } 520 521 pi = &lcore_power_info[lcore_id]; 522 exp_state = POWER_IDLE; 523 /* The power in use state works as a guard variable between 524 * the CPU frequency control initialization and exit process. 525 * The ACQUIRE memory ordering here pairs with the RELEASE 526 * ordering below as lock to make sure the frequency operations 527 * in the critical section are done under the correct state. 528 */ 529 if (!__atomic_compare_exchange_n(&(pi->state), &exp_state, 530 POWER_ONGOING, 0, 531 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 532 RTE_LOG(INFO, POWER, "Power management of lcore %u is " 533 "in use\n", lcore_id); 534 return -1; 535 } 536 537 pi->lcore_id = lcore_id; 538 /* Check and set the governor */ 539 if (power_set_governor_performance(pi) < 0) { 540 RTE_LOG(ERR, POWER, "Cannot set governor of lcore %u to " 541 "performance\n", lcore_id); 542 goto fail; 543 } 544 /* Init for setting lcore frequency */ 545 if (power_init_for_setting_freq(pi) < 0) { 546 RTE_LOG(ERR, POWER, "Cannot init for setting frequency for " 547 "lcore %u\n", lcore_id); 548 goto fail; 549 } 550 551 /* Get the available frequencies */ 552 if (power_get_available_freqs(pi) < 0) { 553 RTE_LOG(ERR, POWER, "Cannot get available frequencies of " 554 "lcore %u\n", lcore_id); 555 goto fail; 556 } 557 558 if (power_get_cur_idx(pi) < 0) { 559 RTE_LOG(ERR, POWER, "Cannot get current frequency " 560 "index of lcore %u\n", lcore_id); 561 goto fail; 562 } 563 564 /* Set freq to max by default */ 565 if (power_pstate_cpufreq_freq_max(lcore_id) < 0) { 566 RTE_LOG(ERR, POWER, "Cannot set frequency of lcore %u " 567 "to max\n", lcore_id); 568 goto fail; 569 } 570 571 RTE_LOG(INFO, POWER, "Initialized successfully for lcore %u " 572 "power management\n", lcore_id); 573 exp_state = POWER_ONGOING; 574 __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_USED, 575 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); 576 577 return 0; 578 579 fail: 580 exp_state = POWER_ONGOING; 581 __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_UNKNOWN, 582 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); 583 584 return -1; 585 } 586 587 int 588 power_pstate_cpufreq_exit(unsigned int lcore_id) 589 { 590 struct pstate_power_info *pi; 591 uint32_t exp_state; 592 593 if (lcore_id >= RTE_MAX_LCORE) { 594 RTE_LOG(ERR, POWER, "Lcore id %u can not exceeds %u\n", 595 lcore_id, RTE_MAX_LCORE - 1U); 596 return -1; 597 } 598 pi = &lcore_power_info[lcore_id]; 599 600 exp_state = POWER_USED; 601 /* The power in use state works as a guard variable between 602 * the CPU frequency control initialization and exit process. 603 * The ACQUIRE memory ordering here pairs with the RELEASE 604 * ordering below as lock to make sure the frequency operations 605 * in the critical section are under done the correct state. 606 */ 607 if (!__atomic_compare_exchange_n(&(pi->state), &exp_state, 608 POWER_ONGOING, 0, 609 __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { 610 RTE_LOG(INFO, POWER, "Power management of lcore %u is " 611 "not used\n", lcore_id); 612 return -1; 613 } 614 615 /* Close FD of setting freq */ 616 fclose(pi->f_cur_min); 617 fclose(pi->f_cur_max); 618 pi->f_cur_min = NULL; 619 pi->f_cur_max = NULL; 620 621 /* Set the governor back to the original */ 622 if (power_set_governor_original(pi) < 0) { 623 RTE_LOG(ERR, POWER, "Cannot set the governor of %u back " 624 "to the original\n", lcore_id); 625 goto fail; 626 } 627 628 RTE_LOG(INFO, POWER, "Power management of lcore %u has exited from " 629 "'performance' mode and been set back to the " 630 "original\n", lcore_id); 631 exp_state = POWER_ONGOING; 632 __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_IDLE, 633 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); 634 635 return 0; 636 637 fail: 638 exp_state = POWER_ONGOING; 639 __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_UNKNOWN, 640 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); 641 642 return -1; 643 } 644 645 646 uint32_t 647 power_pstate_cpufreq_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t num) 648 { 649 struct pstate_power_info *pi; 650 651 if (lcore_id >= RTE_MAX_LCORE) { 652 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 653 return 0; 654 } 655 656 if (freqs == NULL) { 657 RTE_LOG(ERR, POWER, "NULL buffer supplied\n"); 658 return 0; 659 } 660 661 pi = &lcore_power_info[lcore_id]; 662 if (num < pi->nb_freqs) { 663 RTE_LOG(ERR, POWER, "Buffer size is not enough\n"); 664 return 0; 665 } 666 rte_memcpy(freqs, pi->freqs, pi->nb_freqs * sizeof(uint32_t)); 667 668 return pi->nb_freqs; 669 } 670 671 uint32_t 672 power_pstate_cpufreq_get_freq(unsigned int lcore_id) 673 { 674 if (lcore_id >= RTE_MAX_LCORE) { 675 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 676 return RTE_POWER_INVALID_FREQ_INDEX; 677 } 678 679 return lcore_power_info[lcore_id].curr_idx; 680 } 681 682 683 int 684 power_pstate_cpufreq_set_freq(unsigned int lcore_id, uint32_t index) 685 { 686 if (lcore_id >= RTE_MAX_LCORE) { 687 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 688 return -1; 689 } 690 691 return set_freq_internal(&(lcore_power_info[lcore_id]), index); 692 } 693 694 int 695 power_pstate_cpufreq_freq_up(unsigned int lcore_id) 696 { 697 struct pstate_power_info *pi; 698 699 if (lcore_id >= RTE_MAX_LCORE) { 700 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 701 return -1; 702 } 703 704 pi = &lcore_power_info[lcore_id]; 705 if (pi->curr_idx == 0 || 706 (pi->curr_idx == 1 && pi->turbo_available && !pi->turbo_enable)) 707 return 0; 708 709 /* Frequencies in the array are from high to low. */ 710 return set_freq_internal(pi, pi->curr_idx - 1); 711 } 712 713 int 714 power_pstate_cpufreq_freq_down(unsigned int lcore_id) 715 { 716 struct pstate_power_info *pi; 717 718 if (lcore_id >= RTE_MAX_LCORE) { 719 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 720 return -1; 721 } 722 723 pi = &lcore_power_info[lcore_id]; 724 if (pi->curr_idx + 1 == pi->nb_freqs) 725 return 0; 726 727 /* Frequencies in the array are from high to low. */ 728 return set_freq_internal(pi, pi->curr_idx + 1); 729 } 730 731 int 732 power_pstate_cpufreq_freq_max(unsigned int lcore_id) 733 { 734 if (lcore_id >= RTE_MAX_LCORE) { 735 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 736 return -1; 737 } 738 739 /* Frequencies in the array are from high to low. */ 740 if (lcore_power_info[lcore_id].turbo_available) { 741 if (lcore_power_info[lcore_id].turbo_enable) 742 /* Set to Turbo */ 743 return set_freq_internal( 744 &lcore_power_info[lcore_id], 0); 745 else 746 /* Set to max non-turbo */ 747 return set_freq_internal( 748 &lcore_power_info[lcore_id], 1); 749 } else 750 return set_freq_internal(&lcore_power_info[lcore_id], 0); 751 } 752 753 754 int 755 power_pstate_cpufreq_freq_min(unsigned int lcore_id) 756 { 757 struct pstate_power_info *pi; 758 759 if (lcore_id >= RTE_MAX_LCORE) { 760 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 761 return -1; 762 } 763 764 pi = &lcore_power_info[lcore_id]; 765 766 /* Frequencies in the array are from high to low. */ 767 return set_freq_internal(pi, pi->nb_freqs - 1); 768 } 769 770 771 int 772 power_pstate_turbo_status(unsigned int lcore_id) 773 { 774 struct pstate_power_info *pi; 775 776 if (lcore_id >= RTE_MAX_LCORE) { 777 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 778 return -1; 779 } 780 781 pi = &lcore_power_info[lcore_id]; 782 783 return pi->turbo_enable; 784 } 785 786 int 787 power_pstate_enable_turbo(unsigned int lcore_id) 788 { 789 struct pstate_power_info *pi; 790 791 if (lcore_id >= RTE_MAX_LCORE) { 792 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 793 return -1; 794 } 795 796 pi = &lcore_power_info[lcore_id]; 797 798 if (pi->turbo_available) 799 pi->turbo_enable = 1; 800 else { 801 pi->turbo_enable = 0; 802 RTE_LOG(ERR, POWER, 803 "Failed to enable turbo on lcore %u\n", 804 lcore_id); 805 return -1; 806 } 807 808 return 0; 809 } 810 811 812 int 813 power_pstate_disable_turbo(unsigned int lcore_id) 814 { 815 struct pstate_power_info *pi; 816 817 if (lcore_id >= RTE_MAX_LCORE) { 818 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 819 return -1; 820 } 821 822 pi = &lcore_power_info[lcore_id]; 823 824 pi->turbo_enable = 0; 825 826 if (pi->turbo_available && pi->curr_idx <= 1) { 827 /* Try to set freq to max by default coming out of turbo */ 828 if (power_pstate_cpufreq_freq_max(lcore_id) < 0) { 829 RTE_LOG(ERR, POWER, 830 "Failed to set frequency of lcore %u to max\n", 831 lcore_id); 832 return -1; 833 } 834 } 835 836 return 0; 837 } 838 839 840 int power_pstate_get_capabilities(unsigned int lcore_id, 841 struct rte_power_core_capabilities *caps) 842 { 843 struct pstate_power_info *pi; 844 845 if (lcore_id >= RTE_MAX_LCORE) { 846 RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); 847 return -1; 848 } 849 if (caps == NULL) { 850 RTE_LOG(ERR, POWER, "Invalid argument\n"); 851 return -1; 852 } 853 854 pi = &lcore_power_info[lcore_id]; 855 caps->capabilities = 0; 856 caps->turbo = !!(pi->turbo_available); 857 caps->priority = pi->priority_core; 858 859 return 0; 860 } 861