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> 18d26c18c9SAlan Carew #include <rte_power.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 35d26c18c9SAlan Carew struct freq_info { 36d26c18c9SAlan Carew rte_spinlock_t power_sl; 37d26c18c9SAlan Carew uint32_t freqs[RTE_MAX_LCORE_FREQS]; 38d26c18c9SAlan Carew unsigned num_freqs; 39d26c18c9SAlan Carew } __rte_cache_aligned; 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; 70*95f648ffSRory 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++) { 996453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 1007f472f74SDavid Hunt if (rte_power_init(i) < 0) 1017f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1027f472f74SDavid Hunt "Unable to initialize power manager " 103d26c18c9SAlan Carew "for core %u\n", i); 1046453b928SDavid Hunt num_cpus++; 1056453b928SDavid Hunt num_freqs = rte_power_freqs(i, 1066453b928SDavid Hunt global_core_freq_info[i].freqs, 1077f472f74SDavid Hunt RTE_MAX_LCORE_FREQS); 1087f472f74SDavid Hunt if (num_freqs == 0) { 1097f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1107f472f74SDavid Hunt "Unable to get frequency list for core %u\n", 1117f472f74SDavid Hunt i); 1126453b928SDavid Hunt ci->cd[i].oob_enabled = 0; 113d26c18c9SAlan Carew ret = -1; 114d26c18c9SAlan Carew } 1157f472f74SDavid Hunt global_core_freq_info[i].num_freqs = num_freqs; 1166453b928SDavid Hunt 117d26c18c9SAlan Carew rte_spinlock_init(&global_core_freq_info[i].power_sl); 118d26c18c9SAlan Carew } 1196453b928SDavid Hunt if (ci->cd[i].oob_enabled) 1206453b928SDavid Hunt add_core_to_monitor(i); 1216453b928SDavid Hunt } 1226453b928SDavid Hunt RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n", 1236453b928SDavid Hunt num_cpus, ci->core_count); 124d26c18c9SAlan Carew return ret; 125d26c18c9SAlan Carew 126d26c18c9SAlan Carew } 127d26c18c9SAlan Carew 128d26c18c9SAlan Carew uint32_t 129d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num) 130d26c18c9SAlan Carew { 131d26c18c9SAlan Carew uint32_t freq, index; 132d26c18c9SAlan Carew 133751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) { 134d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 135751227a0SDavid Hunt core_num, RTE_MAX_LCORE-1); 136d26c18c9SAlan Carew return -1; 137d26c18c9SAlan Carew } 1386453b928SDavid Hunt if (!(ci.cd[core_num].global_enabled_cpus)) 139d26c18c9SAlan Carew return 0; 140d26c18c9SAlan Carew 141d26c18c9SAlan Carew rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 142d26c18c9SAlan Carew index = rte_power_get_freq(core_num); 143d26c18c9SAlan Carew rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 1443f1fc5f2SDavid Hunt if (index >= RTE_MAX_LCORE_FREQS) 145d26c18c9SAlan Carew freq = 0; 146d26c18c9SAlan Carew else 147d26c18c9SAlan Carew freq = global_core_freq_info[core_num].freqs[index]; 148d26c18c9SAlan Carew 149d26c18c9SAlan Carew return freq; 150d26c18c9SAlan Carew } 151d26c18c9SAlan Carew 152d26c18c9SAlan Carew int 153d26c18c9SAlan Carew power_manager_exit(void) 154d26c18c9SAlan Carew { 155d26c18c9SAlan Carew unsigned int i; 156d26c18c9SAlan Carew int ret = 0; 1576453b928SDavid Hunt struct core_info *ci; 158c12ade20SDavid Hunt unsigned int max_core_num; 159d26c18c9SAlan Carew 1606453b928SDavid Hunt ci = get_core_info(); 1616453b928SDavid Hunt if (!ci) { 1626453b928SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1636453b928SDavid Hunt "Failed to get core info!\n"); 1646453b928SDavid Hunt return -1; 1656453b928SDavid Hunt } 1666453b928SDavid Hunt 167751227a0SDavid Hunt if (ci->core_count > RTE_MAX_LCORE) 168751227a0SDavid Hunt max_core_num = RTE_MAX_LCORE; 169c12ade20SDavid Hunt else 170c12ade20SDavid Hunt max_core_num = ci->core_count; 171c12ade20SDavid Hunt 172c12ade20SDavid Hunt for (i = 0; i < max_core_num; i++) { 1736453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 174d26c18c9SAlan Carew if (rte_power_exit(i) < 0) { 175d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 176d26c18c9SAlan Carew "for core %u\n", i); 177d26c18c9SAlan Carew ret = -1; 178d26c18c9SAlan Carew } 1796453b928SDavid Hunt ci->cd[i].global_enabled_cpus = 0; 180d26c18c9SAlan Carew } 1816453b928SDavid Hunt remove_core_from_monitor(i); 1826453b928SDavid Hunt } 183d26c18c9SAlan Carew return ret; 184d26c18c9SAlan Carew } 185d26c18c9SAlan Carew 186d26c18c9SAlan Carew int 187d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num) 188d26c18c9SAlan Carew { 189d26c18c9SAlan Carew int ret = 0; 190d26c18c9SAlan Carew 191d26c18c9SAlan Carew POWER_SCALE_CORE(up, core_num, ret); 192d26c18c9SAlan Carew return ret; 193d26c18c9SAlan Carew } 194d26c18c9SAlan Carew 195d26c18c9SAlan Carew int 196d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num) 197d26c18c9SAlan Carew { 198d26c18c9SAlan Carew int ret = 0; 199d26c18c9SAlan Carew 200d26c18c9SAlan Carew POWER_SCALE_CORE(down, core_num, ret); 201d26c18c9SAlan Carew return ret; 202d26c18c9SAlan Carew } 203d26c18c9SAlan Carew 204d26c18c9SAlan Carew int 205d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num) 206d26c18c9SAlan Carew { 207d26c18c9SAlan Carew int ret = 0; 208d26c18c9SAlan Carew 209d26c18c9SAlan Carew POWER_SCALE_CORE(min, core_num, ret); 210d26c18c9SAlan Carew return ret; 211d26c18c9SAlan Carew } 212d26c18c9SAlan Carew 213d26c18c9SAlan Carew int 214d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num) 215d26c18c9SAlan Carew { 216d26c18c9SAlan Carew int ret = 0; 217d26c18c9SAlan Carew 218d26c18c9SAlan Carew POWER_SCALE_CORE(max, core_num, ret); 219d26c18c9SAlan Carew return ret; 220d26c18c9SAlan Carew } 221567997b9SDavid Hunt 222567997b9SDavid Hunt int 223567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num) 224567997b9SDavid Hunt { 225567997b9SDavid Hunt int ret = 0; 226567997b9SDavid Hunt 227567997b9SDavid Hunt POWER_SCALE_CORE(enable_turbo, core_num, ret); 228567997b9SDavid Hunt return ret; 229567997b9SDavid Hunt } 230567997b9SDavid Hunt 231567997b9SDavid Hunt int 232567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num) 233567997b9SDavid Hunt { 234567997b9SDavid Hunt int ret = 0; 235567997b9SDavid Hunt 236567997b9SDavid Hunt POWER_SCALE_CORE(disable_turbo, core_num, ret); 237567997b9SDavid Hunt return ret; 238567997b9SDavid Hunt } 2397f472f74SDavid Hunt 2407f472f74SDavid Hunt int 2417f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num) 2427f472f74SDavid Hunt { 2437f472f74SDavid Hunt int ret = 0; 2446453b928SDavid Hunt struct core_info *ci; 2457f472f74SDavid Hunt 2466453b928SDavid Hunt ci = get_core_info(); 247751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) 2487f472f74SDavid Hunt return -1; 2496453b928SDavid Hunt if (!(ci->cd[core_num].global_enabled_cpus)) 2507f472f74SDavid Hunt return -1; 2517f472f74SDavid Hunt rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 2527f472f74SDavid Hunt ret = rte_power_set_freq(core_num, 2537f472f74SDavid Hunt global_core_freq_info[core_num].num_freqs / 2); 2547f472f74SDavid Hunt rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 2557f472f74SDavid Hunt return ret; 2567f472f74SDavid Hunt } 257