X-Git-Url: http://git.droids-corp.org/?a=blobdiff_plain;f=lib%2Flibrte_power%2Fpower_pstate_cpufreq.c;h=edf6328e5ff0db50bd9283f46062f26fda68db28;hb=4a91344b5e06081f8e2254266bb469489f6633d8;hp=0f8e8f9706b53443f8e352b71ea4f045eb9beb27;hpb=de394915dfa12628fd55680dadeda521e53ef948;p=dpdk.git diff --git a/lib/librte_power/power_pstate_cpufreq.c b/lib/librte_power/power_pstate_cpufreq.c index 0f8e8f9706..edf6328e5f 100644 --- a/lib/librte_power/power_pstate_cpufreq.c +++ b/lib/librte_power/power_pstate_cpufreq.c @@ -15,7 +15,8 @@ #include #include -#include +#include +#include #include "power_pstate_cpufreq.h" #include "power_common.h" @@ -31,7 +32,7 @@ #define FOPEN_OR_ERR_RET(f, retval) do { \ if ((f) == NULL) { \ - RTE_LOG(ERR, POWER, "File not openned\n"); \ + RTE_LOG(ERR, POWER, "File not opened\n"); \ return retval; \ } \ } while (0) @@ -50,6 +51,9 @@ } \ } while (0) +/* macros used for rounding frequency to nearest 100000 */ +#define FREQ_ROUNDING_DELTA 50000 +#define ROUND_FREQ_TO_N_100000 100000 #define POWER_CONVERT_TO_DECIMAL 10 #define BUS_FREQ 100000 @@ -67,6 +71,9 @@ "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_max_freq" #define POWER_SYSFILE_BASE_MIN_FREQ \ "/sys/devices/system/cpu/cpu%u/cpufreq/cpuinfo_min_freq" +#define POWER_SYSFILE_BASE_FREQ \ + "/sys/devices/system/cpu/cpu%u/cpufreq/base_frequency" +#define POWER_PSTATE_DRIVER "intel_pstate" #define POWER_MSR_PATH "/dev/cpu/%u/msr" /* @@ -94,9 +101,11 @@ struct pstate_power_info { uint32_t curr_idx; /**< Freq index in freqs array */ uint32_t non_turbo_max_ratio; /**< Non Turbo Max ratio */ uint32_t sys_max_freq; /**< system wide max freq */ - volatile uint32_t state; /**< Power in use state */ + uint32_t core_base_freq; /**< core base freq */ + uint32_t state; /**< Power in use state */ uint16_t turbo_available; /**< Turbo Boost available */ uint16_t turbo_enable; /**< Turbo Boost enable/disable */ + uint16_t priority_core; /**< High Performance core */ } __rte_cache_aligned; @@ -145,10 +154,15 @@ out: close(fd); static int power_init_for_setting_freq(struct pstate_power_info *pi) { - FILE *f_min, *f_max; + FILE *f_min, *f_max, *f_base; char fullpath_min[PATH_MAX]; char fullpath_max[PATH_MAX]; + char fullpath_base[PATH_MAX]; + char buf_base[BUFSIZ]; + char *s_base; + uint32_t base_ratio = 0; uint64_t max_non_turbo = 0; + int ret_val = 0; snprintf(fullpath_min, sizeof(fullpath_min), POWER_SYSFILE_MIN_FREQ, pi->lcore_id); @@ -160,15 +174,40 @@ power_init_for_setting_freq(struct pstate_power_info *pi) pi->lcore_id); f_max = fopen(fullpath_max, "rw+"); + if (f_max == NULL) + fclose(f_min); + FOPEN_OR_ERR_RET(f_max, -1); pi->f_cur_min = f_min; pi->f_cur_max = f_max; + snprintf(fullpath_base, sizeof(fullpath_base), POWER_SYSFILE_BASE_FREQ, + pi->lcore_id); + + f_base = fopen(fullpath_base, "r"); + if (f_base == NULL) { + /* No sysfs base_frequency, that's OK, continue without */ + base_ratio = 0; + } else { + s_base = fgets(buf_base, sizeof(buf_base), f_base); + FOPS_OR_NULL_GOTO(s_base, out); + + buf_base[BUFSIZ-1] = '\0'; + if (strlen(buf_base)) + /* Strip off terminating '\n' */ + strtok(buf_base, "\n"); + + base_ratio = strtoul(buf_base, NULL, POWER_CONVERT_TO_DECIMAL) + / BUS_FREQ; + } + /* Add MSR read to detect turbo status */ - if (power_rdmsr(PLATFORM_INFO, &max_non_turbo, pi->lcore_id) < 0) - return -1; + if (power_rdmsr(PLATFORM_INFO, &max_non_turbo, pi->lcore_id) < 0) { + ret_val = -1; + goto out; + } max_non_turbo = (max_non_turbo&NON_TURBO_MASK)>>NON_TURBO_OFFSET; @@ -176,7 +215,20 @@ power_init_for_setting_freq(struct pstate_power_info *pi) pi->non_turbo_max_ratio = max_non_turbo; - return 0; + /* + * If base_frequency is reported as greater than the maximum + * non-turbo frequency, then mark it as a high priority core. + */ + if (base_ratio > max_non_turbo) + pi->priority_core = 1; + else + pi->priority_core = 0; + pi->core_base_freq = base_ratio * BUS_FREQ; + +out: + if (f_base != NULL) + fclose(f_base); + return ret_val; } static int @@ -212,9 +264,15 @@ set_freq_internal(struct pstate_power_info *pi, uint32_t idx) } /* Turbo is available and enabled, first freq bucket is sys max freq */ - if (pi->turbo_available && pi->turbo_enable && (idx == 0)) - target_freq = pi->sys_max_freq; - else + if (pi->turbo_available && idx == 0) { + if (pi->turbo_enable) + target_freq = pi->sys_max_freq; + else { + RTE_LOG(ERR, POWER, "Turbo is off, frequency can't be scaled up more %u\n", + pi->lcore_id); + return -1; + } + } else target_freq = pi->freqs[idx]; /* Decrease freq, the min freq should be updated first */ @@ -232,7 +290,7 @@ set_freq_internal(struct pstate_power_info *pi, uint32_t idx) return -1; } - POWER_DEBUG_TRACE("Freqency '%u' to be set for lcore %u\n", + POWER_DEBUG_TRACE("Frequency '%u' to be set for lcore %u\n", target_freq, pi->lcore_id); fflush(pi->f_cur_min); @@ -255,7 +313,7 @@ set_freq_internal(struct pstate_power_info *pi, uint32_t idx) return -1; } - POWER_DEBUG_TRACE("Freqency '%u' to be set for lcore %u\n", + POWER_DEBUG_TRACE("Frequency '%u' to be set for lcore %u\n", target_freq, pi->lcore_id); fflush(pi->f_cur_max); @@ -289,6 +347,8 @@ power_set_governor_performance(struct pstate_power_info *pi) s = fgets(buf, sizeof(buf), f); FOPS_OR_NULL_GOTO(s, out); + /* Strip off terminating '\n' */ + strtok(buf, "\n"); /* Check if current governor is performance */ if (strncmp(buf, POWER_GOVERNOR_PERF, @@ -299,7 +359,7 @@ power_set_governor_performance(struct pstate_power_info *pi) goto out; } /* Save the original governor */ - snprintf(pi->governor_ori, sizeof(pi->governor_ori), "%s", buf); + strlcpy(pi->governor_ori, buf, sizeof(pi->governor_ori)); /* Write 'performance' to the governor */ val = fseek(f, 0, SEEK_SET); @@ -398,6 +458,9 @@ power_get_available_freqs(struct pstate_power_info *pi) FOPEN_OR_ERR_RET(f_min, ret); f_max = fopen(fullpath_max, "r"); + if (f_max == NULL) + fclose(f_min); + FOPEN_OR_ERR_RET(f_max, ret); s_min = fgets(buf_min, sizeof(buf_min), f_min); @@ -424,7 +487,10 @@ power_get_available_freqs(struct pstate_power_info *pi) pi->sys_max_freq = sys_max_freq; - base_max_freq = pi->non_turbo_max_ratio * BUS_FREQ; + if (pi->priority_core == 1) + base_max_freq = pi->core_base_freq; + else + base_max_freq = pi->non_turbo_max_ratio * BUS_FREQ; POWER_DEBUG_TRACE("sys min %u, sys max %u, base_max %u\n", sys_min_freq, @@ -468,10 +534,68 @@ out: return ret; } +static int +power_get_cur_idx(struct pstate_power_info *pi) +{ + FILE *f_cur; + int ret = -1; + char *p_cur; + char buf_cur[BUFSIZ]; + char fullpath_cur[PATH_MAX]; + char *s_cur; + uint32_t sys_cur_freq = 0; + unsigned int i; + + snprintf(fullpath_cur, sizeof(fullpath_cur), + POWER_SYSFILE_CUR_FREQ, + pi->lcore_id); + f_cur = fopen(fullpath_cur, "r"); + FOPEN_OR_ERR_RET(f_cur, ret); + + /* initialize the cur_idx to matching current frequency freq index */ + s_cur = fgets(buf_cur, sizeof(buf_cur), f_cur); + FOPS_OR_NULL_GOTO(s_cur, fail); + + p_cur = strchr(buf_cur, '\n'); + if (p_cur != NULL) + *p_cur = 0; + sys_cur_freq = strtoul(buf_cur, &p_cur, POWER_CONVERT_TO_DECIMAL); + + /* convert the frequency to nearest 100000 value + * Ex: if sys_cur_freq=1396789 then freq_conv=1400000 + * Ex: if sys_cur_freq=800030 then freq_conv=800000 + * Ex: if sys_cur_freq=800030 then freq_conv=800000 + */ + unsigned int freq_conv = 0; + freq_conv = (sys_cur_freq + FREQ_ROUNDING_DELTA) + / ROUND_FREQ_TO_N_100000; + freq_conv = freq_conv * ROUND_FREQ_TO_N_100000; + + for (i = 0; i < pi->nb_freqs; i++) { + if (freq_conv == pi->freqs[i]) { + pi->curr_idx = i; + break; + } + } + + fclose(f_cur); + return 0; +fail: + fclose(f_cur); + return ret; +} + +int +power_pstate_cpufreq_check_supported(void) +{ + return cpufreq_check_scaling_driver(POWER_PSTATE_DRIVER); +} + int power_pstate_cpufreq_init(unsigned int lcore_id) { struct pstate_power_info *pi; + uint32_t exp_state; if (lcore_id >= RTE_MAX_LCORE) { RTE_LOG(ERR, POWER, "Lcore id %u can not exceed %u\n", @@ -480,8 +604,16 @@ power_pstate_cpufreq_init(unsigned int lcore_id) } pi = &lcore_power_info[lcore_id]; - if (rte_atomic32_cmpset(&(pi->state), POWER_IDLE, POWER_ONGOING) - == 0) { + exp_state = POWER_IDLE; + /* The power in use state works as a guard variable between + * the CPU frequency control initialization and exit process. + * The ACQUIRE memory ordering here pairs with the RELEASE + * ordering below as lock to make sure the frequency operations + * in the critical section are done under the correct state. + */ + if (!__atomic_compare_exchange_n(&(pi->state), &exp_state, + POWER_ONGOING, 0, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { RTE_LOG(INFO, POWER, "Power management of lcore %u is " "in use\n", lcore_id); return -1; @@ -508,6 +640,11 @@ power_pstate_cpufreq_init(unsigned int lcore_id) goto fail; } + if (power_get_cur_idx(pi) < 0) { + RTE_LOG(ERR, POWER, "Cannot get current frequency " + "index of lcore %u\n", lcore_id); + goto fail; + } /* Set freq to max by default */ if (power_pstate_cpufreq_freq_max(lcore_id) < 0) { @@ -518,12 +655,16 @@ power_pstate_cpufreq_init(unsigned int lcore_id) RTE_LOG(INFO, POWER, "Initialized successfully for lcore %u " "power management\n", lcore_id); - rte_atomic32_cmpset(&(pi->state), POWER_ONGOING, POWER_USED); + exp_state = POWER_ONGOING; + __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_USED, + 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return 0; fail: - rte_atomic32_cmpset(&(pi->state), POWER_ONGOING, POWER_UNKNOWN); + exp_state = POWER_ONGOING; + __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_UNKNOWN, + 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return -1; } @@ -532,6 +673,7 @@ int power_pstate_cpufreq_exit(unsigned int lcore_id) { struct pstate_power_info *pi; + uint32_t exp_state; if (lcore_id >= RTE_MAX_LCORE) { RTE_LOG(ERR, POWER, "Lcore id %u can not exceeds %u\n", @@ -540,8 +682,16 @@ power_pstate_cpufreq_exit(unsigned int lcore_id) } pi = &lcore_power_info[lcore_id]; - if (rte_atomic32_cmpset(&(pi->state), POWER_USED, POWER_ONGOING) - == 0) { + exp_state = POWER_USED; + /* The power in use state works as a guard variable between + * the CPU frequency control initialization and exit process. + * The ACQUIRE memory ordering here pairs with the RELEASE + * ordering below as lock to make sure the frequency operations + * in the critical section are under done the correct state. + */ + if (!__atomic_compare_exchange_n(&(pi->state), &exp_state, + POWER_ONGOING, 0, + __ATOMIC_ACQUIRE, __ATOMIC_RELAXED)) { RTE_LOG(INFO, POWER, "Power management of lcore %u is " "not used\n", lcore_id); return -1; @@ -563,12 +713,16 @@ power_pstate_cpufreq_exit(unsigned int lcore_id) RTE_LOG(INFO, POWER, "Power management of lcore %u has exited from " "'performance' mode and been set back to the " "original\n", lcore_id); - rte_atomic32_cmpset(&(pi->state), POWER_ONGOING, POWER_IDLE); + exp_state = POWER_ONGOING; + __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_IDLE, + 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return 0; fail: - rte_atomic32_cmpset(&(pi->state), POWER_ONGOING, POWER_UNKNOWN); + exp_state = POWER_ONGOING; + __atomic_compare_exchange_n(&(pi->state), &exp_state, POWER_UNKNOWN, + 0, __ATOMIC_RELEASE, __ATOMIC_RELAXED); return -1; } @@ -581,7 +735,12 @@ power_pstate_cpufreq_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t num) if (lcore_id >= RTE_MAX_LCORE) { RTE_LOG(ERR, POWER, "Invalid lcore ID\n"); - return -1; + return 0; + } + + if (freqs == NULL) { + RTE_LOG(ERR, POWER, "NULL buffer supplied\n"); + return 0; } pi = &lcore_power_info[lcore_id]; @@ -628,7 +787,8 @@ power_pstate_cpufreq_freq_up(unsigned int lcore_id) } pi = &lcore_power_info[lcore_id]; - if (pi->curr_idx == 0) + if (pi->curr_idx == 0 || + (pi->curr_idx == 1 && pi->turbo_available && !pi->turbo_enable)) return 0; /* Frequencies in the array are from high to low. */ @@ -748,6 +908,15 @@ power_pstate_disable_turbo(unsigned int lcore_id) pi->turbo_enable = 0; + if (pi->turbo_available && pi->curr_idx <= 1) { + /* Try to set freq to max by default coming out of turbo */ + if (power_pstate_cpufreq_freq_max(lcore_id) < 0) { + RTE_LOG(ERR, POWER, + "Failed to set frequency of lcore %u to max\n", + lcore_id); + return -1; + } + } return 0; } @@ -770,6 +939,7 @@ int power_pstate_get_capabilities(unsigned int lcore_id, pi = &lcore_power_info[lcore_id]; caps->capabilities = 0; caps->turbo = !!(pi->turbo_available); + caps->priority = pi->priority_core; return 0; }