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