13998e2a0SBruce Richardson /* SPDX-License-Identifier: BSD-3-Clause 23998e2a0SBruce Richardson * Copyright(c) 2010-2014 Intel Corporation 3d26c18c9SAlan Carew */ 4d26c18c9SAlan Carew 5d26c18c9SAlan Carew #include <stdio.h> 6d26c18c9SAlan Carew #include <stdlib.h> 7d26c18c9SAlan Carew #include <stdint.h> 8d26c18c9SAlan Carew #include <inttypes.h> 9d26c18c9SAlan Carew #include <fcntl.h> 10d26c18c9SAlan Carew #include <unistd.h> 11d26c18c9SAlan Carew #include <dirent.h> 12d26c18c9SAlan Carew #include <errno.h> 13d26c18c9SAlan Carew 1499a968faSDavid Hunt #include <sys/sysinfo.h> 15d26c18c9SAlan Carew #include <sys/types.h> 16d26c18c9SAlan Carew 17d26c18c9SAlan Carew #include <rte_log.h> 18*f30a1bbdSSivaprasad Tummala #include <rte_power_cpufreq.h> 19d26c18c9SAlan Carew #include <rte_spinlock.h> 20d26c18c9SAlan Carew 216453b928SDavid Hunt #include "channel_manager.h" 22d26c18c9SAlan Carew #include "power_manager.h" 236453b928SDavid Hunt #include "oob_monitor.h" 24d26c18c9SAlan Carew 25d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \ 266453b928SDavid Hunt if (core_num >= ci.core_count) \ 27d26c18c9SAlan Carew return -1; \ 286453b928SDavid Hunt if (!(ci.cd[core_num].global_enabled_cpus)) \ 29d26c18c9SAlan Carew return -1; \ 30d26c18c9SAlan Carew rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \ 31d26c18c9SAlan Carew ret = rte_power_freq_##DIRECTION(core_num); \ 32d26c18c9SAlan Carew rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \ 33d26c18c9SAlan Carew } while (0) 34d26c18c9SAlan Carew 357e06c0deSTyler Retzlaff struct __rte_cache_aligned freq_info { 36d26c18c9SAlan Carew rte_spinlock_t power_sl; 37d26c18c9SAlan Carew uint32_t freqs[RTE_MAX_LCORE_FREQS]; 38d26c18c9SAlan Carew unsigned num_freqs; 397e06c0deSTyler Retzlaff }; 40d26c18c9SAlan Carew 41751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE]; 42d26c18c9SAlan Carew 4399a968faSDavid Hunt struct core_info ci; 44d26c18c9SAlan Carew 45d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id" 46d26c18c9SAlan Carew 4799a968faSDavid Hunt struct core_info * 4899a968faSDavid Hunt get_core_info(void) 4999a968faSDavid Hunt { 5099a968faSDavid Hunt return &ci; 5199a968faSDavid Hunt } 5299a968faSDavid Hunt 5399a968faSDavid Hunt int 5499a968faSDavid Hunt core_info_init(void) 5599a968faSDavid Hunt { 5699a968faSDavid Hunt struct core_info *ci; 5799a968faSDavid Hunt int i; 5899a968faSDavid Hunt 5999a968faSDavid Hunt ci = get_core_info(); 6099a968faSDavid Hunt 6199a968faSDavid Hunt ci->core_count = get_nprocs_conf(); 6299a968faSDavid Hunt ci->cd = malloc(ci->core_count * sizeof(struct core_details)); 6331c9a664SDavid Hunt memset(ci->cd, 0, ci->core_count * sizeof(struct core_details)); 6499a968faSDavid Hunt if (!ci->cd) { 6599a968faSDavid Hunt RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info."); 6699a968faSDavid Hunt return -1; 6799a968faSDavid Hunt } 6899a968faSDavid Hunt for (i = 0; i < ci->core_count; i++) { 6999a968faSDavid Hunt ci->cd[i].global_enabled_cpus = 1; 7095f648ffSRory Sexton ci->cd[i].branch_ratio_threshold = BRANCH_RATIO_THRESHOLD; 7199a968faSDavid Hunt } 7299a968faSDavid Hunt printf("%d cores in system\n", ci->core_count); 7399a968faSDavid Hunt return 0; 7499a968faSDavid Hunt } 7599a968faSDavid Hunt 76d26c18c9SAlan Carew int 77d26c18c9SAlan Carew power_manager_init(void) 78d26c18c9SAlan Carew { 796453b928SDavid Hunt unsigned int i, num_cpus = 0, num_freqs = 0; 80d26c18c9SAlan Carew int ret = 0; 816453b928SDavid Hunt struct core_info *ci; 82c12ade20SDavid Hunt unsigned int max_core_num; 83d26c18c9SAlan Carew 846ff7b996SDavid Hunt rte_power_set_env(PM_ENV_NOT_SET); 856453b928SDavid Hunt 866453b928SDavid Hunt ci = get_core_info(); 876453b928SDavid Hunt if (!ci) { 886453b928SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 896453b928SDavid Hunt "Failed to get core info!\n"); 90d26c18c9SAlan Carew return -1; 91d26c18c9SAlan Carew } 926453b928SDavid Hunt 93751227a0SDavid Hunt if (ci->core_count > RTE_MAX_LCORE) 94751227a0SDavid Hunt max_core_num = RTE_MAX_LCORE; 95c12ade20SDavid Hunt else 96c12ade20SDavid Hunt max_core_num = ci->core_count; 97c12ade20SDavid Hunt 98c12ade20SDavid Hunt for (i = 0; i < max_core_num; i++) { 99b49c677aSDavid Hunt if (rte_lcore_index(i) == -1) 100b49c677aSDavid Hunt continue; 101b49c677aSDavid Hunt 1026453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 1037f472f74SDavid Hunt if (rte_power_init(i) < 0) 1047f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1057f472f74SDavid Hunt "Unable to initialize power manager " 106d26c18c9SAlan Carew "for core %u\n", i); 1076453b928SDavid Hunt num_cpus++; 1086453b928SDavid Hunt num_freqs = rte_power_freqs(i, 1096453b928SDavid Hunt global_core_freq_info[i].freqs, 1107f472f74SDavid Hunt RTE_MAX_LCORE_FREQS); 1117f472f74SDavid Hunt if (num_freqs == 0) { 1127f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1137f472f74SDavid Hunt "Unable to get frequency list for core %u\n", 1147f472f74SDavid Hunt i); 1156453b928SDavid Hunt ci->cd[i].oob_enabled = 0; 116d26c18c9SAlan Carew ret = -1; 117d26c18c9SAlan Carew } 1187f472f74SDavid Hunt global_core_freq_info[i].num_freqs = num_freqs; 1196453b928SDavid Hunt 120d26c18c9SAlan Carew rte_spinlock_init(&global_core_freq_info[i].power_sl); 121d26c18c9SAlan Carew } 1226453b928SDavid Hunt if (ci->cd[i].oob_enabled) 1236453b928SDavid Hunt add_core_to_monitor(i); 1246453b928SDavid Hunt } 1256453b928SDavid Hunt RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n", 1266453b928SDavid Hunt num_cpus, ci->core_count); 127d26c18c9SAlan Carew return ret; 128d26c18c9SAlan Carew 129d26c18c9SAlan Carew } 130d26c18c9SAlan Carew 131d26c18c9SAlan Carew uint32_t 132d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num) 133d26c18c9SAlan Carew { 134d26c18c9SAlan Carew uint32_t freq, index; 135d26c18c9SAlan Carew 136751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) { 137d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 138751227a0SDavid Hunt core_num, RTE_MAX_LCORE-1); 139d26c18c9SAlan Carew return -1; 140d26c18c9SAlan Carew } 1416453b928SDavid Hunt if (!(ci.cd[core_num].global_enabled_cpus)) 142d26c18c9SAlan Carew return 0; 143d26c18c9SAlan Carew 144d26c18c9SAlan Carew rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 145d26c18c9SAlan Carew index = rte_power_get_freq(core_num); 146d26c18c9SAlan Carew rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 1473f1fc5f2SDavid Hunt if (index >= RTE_MAX_LCORE_FREQS) 148d26c18c9SAlan Carew freq = 0; 149d26c18c9SAlan Carew else 150d26c18c9SAlan Carew freq = global_core_freq_info[core_num].freqs[index]; 151d26c18c9SAlan Carew 152d26c18c9SAlan Carew return freq; 153d26c18c9SAlan Carew } 154d26c18c9SAlan Carew 155d26c18c9SAlan Carew int 156d26c18c9SAlan Carew power_manager_exit(void) 157d26c18c9SAlan Carew { 158d26c18c9SAlan Carew unsigned int i; 159d26c18c9SAlan Carew int ret = 0; 1606453b928SDavid Hunt struct core_info *ci; 161c12ade20SDavid Hunt unsigned int max_core_num; 162d26c18c9SAlan Carew 1636453b928SDavid Hunt ci = get_core_info(); 1646453b928SDavid Hunt if (!ci) { 1656453b928SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1666453b928SDavid Hunt "Failed to get core info!\n"); 1676453b928SDavid Hunt return -1; 1686453b928SDavid Hunt } 1696453b928SDavid Hunt 170751227a0SDavid Hunt if (ci->core_count > RTE_MAX_LCORE) 171751227a0SDavid Hunt max_core_num = RTE_MAX_LCORE; 172c12ade20SDavid Hunt else 173c12ade20SDavid Hunt max_core_num = ci->core_count; 174c12ade20SDavid Hunt 175c12ade20SDavid Hunt for (i = 0; i < max_core_num; i++) { 176b49c677aSDavid Hunt if (rte_lcore_index(i) == -1) 177b49c677aSDavid Hunt continue; 178b49c677aSDavid Hunt 1796453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 180d26c18c9SAlan Carew if (rte_power_exit(i) < 0) { 181d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 182d26c18c9SAlan Carew "for core %u\n", i); 183d26c18c9SAlan Carew ret = -1; 184d26c18c9SAlan Carew } 1856453b928SDavid Hunt ci->cd[i].global_enabled_cpus = 0; 186d26c18c9SAlan Carew } 1876453b928SDavid Hunt remove_core_from_monitor(i); 1886453b928SDavid Hunt } 189d26c18c9SAlan Carew return ret; 190d26c18c9SAlan Carew } 191d26c18c9SAlan Carew 192d26c18c9SAlan Carew int 193d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num) 194d26c18c9SAlan Carew { 195d26c18c9SAlan Carew int ret = 0; 196d26c18c9SAlan Carew 197d26c18c9SAlan Carew POWER_SCALE_CORE(up, core_num, ret); 198d26c18c9SAlan Carew return ret; 199d26c18c9SAlan Carew } 200d26c18c9SAlan Carew 201d26c18c9SAlan Carew int 202d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num) 203d26c18c9SAlan Carew { 204d26c18c9SAlan Carew int ret = 0; 205d26c18c9SAlan Carew 206d26c18c9SAlan Carew POWER_SCALE_CORE(down, core_num, ret); 207d26c18c9SAlan Carew return ret; 208d26c18c9SAlan Carew } 209d26c18c9SAlan Carew 210d26c18c9SAlan Carew int 211d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num) 212d26c18c9SAlan Carew { 213d26c18c9SAlan Carew int ret = 0; 214d26c18c9SAlan Carew 215d26c18c9SAlan Carew POWER_SCALE_CORE(min, core_num, ret); 216d26c18c9SAlan Carew return ret; 217d26c18c9SAlan Carew } 218d26c18c9SAlan Carew 219d26c18c9SAlan Carew int 220d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num) 221d26c18c9SAlan Carew { 222d26c18c9SAlan Carew int ret = 0; 223d26c18c9SAlan Carew 224d26c18c9SAlan Carew POWER_SCALE_CORE(max, core_num, ret); 225d26c18c9SAlan Carew return ret; 226d26c18c9SAlan Carew } 227567997b9SDavid Hunt 228567997b9SDavid Hunt int 229567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num) 230567997b9SDavid Hunt { 231567997b9SDavid Hunt int ret = 0; 232567997b9SDavid Hunt 233567997b9SDavid Hunt POWER_SCALE_CORE(enable_turbo, core_num, ret); 234567997b9SDavid Hunt return ret; 235567997b9SDavid Hunt } 236567997b9SDavid Hunt 237567997b9SDavid Hunt int 238567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num) 239567997b9SDavid Hunt { 240567997b9SDavid Hunt int ret = 0; 241567997b9SDavid Hunt 242567997b9SDavid Hunt POWER_SCALE_CORE(disable_turbo, core_num, ret); 243567997b9SDavid Hunt return ret; 244567997b9SDavid Hunt } 2457f472f74SDavid Hunt 2467f472f74SDavid Hunt int 2477f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num) 2487f472f74SDavid Hunt { 2497f472f74SDavid Hunt int ret = 0; 2506453b928SDavid Hunt struct core_info *ci; 2517f472f74SDavid Hunt 2526453b928SDavid Hunt ci = get_core_info(); 253751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) 2547f472f74SDavid Hunt return -1; 2556453b928SDavid Hunt if (!(ci->cd[core_num].global_enabled_cpus)) 2567f472f74SDavid Hunt return -1; 2577f472f74SDavid Hunt rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 2587f472f74SDavid Hunt ret = rte_power_set_freq(core_num, 2597f472f74SDavid Hunt global_core_freq_info[core_num].num_freqs / 2); 2607f472f74SDavid Hunt rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 2617f472f74SDavid Hunt return ret; 2627f472f74SDavid Hunt } 263