LCOV - code coverage report
Current view: top level - lib/power - power_pstate_cpufreq.c (source / functions) Hit Total Coverage
Test: Code coverage Lines: 13 335 3.9 %
Date: 2024-01-22 15:35:40 Functions: 1 19 5.3 %
Legend: Lines: hit not hit | Branches: + taken - not taken # not executed Branches: 3 184 1.6 %

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

Generated by: LCOV version 1.14