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