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 <sys/un.h> 10d26c18c9SAlan Carew #include <fcntl.h> 11d26c18c9SAlan Carew #include <unistd.h> 12d26c18c9SAlan Carew #include <dirent.h> 13d26c18c9SAlan Carew #include <errno.h> 14d26c18c9SAlan Carew 1599a968faSDavid Hunt #include <sys/sysinfo.h> 16d26c18c9SAlan Carew #include <sys/types.h> 17d26c18c9SAlan Carew 18d26c18c9SAlan Carew #include <rte_log.h> 19d26c18c9SAlan Carew #include <rte_power.h> 20d26c18c9SAlan Carew #include <rte_spinlock.h> 21d26c18c9SAlan Carew 226453b928SDavid Hunt #include "channel_manager.h" 23d26c18c9SAlan Carew #include "power_manager.h" 246453b928SDavid Hunt #include "oob_monitor.h" 25d26c18c9SAlan Carew 26d26c18c9SAlan Carew #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \ 276453b928SDavid Hunt if (core_num >= ci.core_count) \ 28d26c18c9SAlan Carew return -1; \ 296453b928SDavid Hunt if (!(ci.cd[core_num].global_enabled_cpus)) \ 30d26c18c9SAlan Carew return -1; \ 31d26c18c9SAlan Carew rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \ 32d26c18c9SAlan Carew ret = rte_power_freq_##DIRECTION(core_num); \ 33d26c18c9SAlan Carew rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \ 34d26c18c9SAlan Carew } while (0) 35d26c18c9SAlan Carew 36d26c18c9SAlan Carew struct freq_info { 37d26c18c9SAlan Carew rte_spinlock_t power_sl; 38d26c18c9SAlan Carew uint32_t freqs[RTE_MAX_LCORE_FREQS]; 39d26c18c9SAlan Carew unsigned num_freqs; 40d26c18c9SAlan Carew } __rte_cache_aligned; 41d26c18c9SAlan Carew 42751227a0SDavid Hunt static struct freq_info global_core_freq_info[RTE_MAX_LCORE]; 43d26c18c9SAlan Carew 4499a968faSDavid Hunt struct core_info ci; 45d26c18c9SAlan Carew 46d26c18c9SAlan Carew #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id" 47d26c18c9SAlan Carew 4899a968faSDavid Hunt struct core_info * 4999a968faSDavid Hunt get_core_info(void) 5099a968faSDavid Hunt { 5199a968faSDavid Hunt return &ci; 5299a968faSDavid Hunt } 5399a968faSDavid Hunt 5499a968faSDavid Hunt int 5599a968faSDavid Hunt core_info_init(void) 5699a968faSDavid Hunt { 5799a968faSDavid Hunt struct core_info *ci; 5899a968faSDavid Hunt int i; 5999a968faSDavid Hunt 6099a968faSDavid Hunt ci = get_core_info(); 6199a968faSDavid Hunt 6299a968faSDavid Hunt ci->core_count = get_nprocs_conf(); 63711f43baSDavid Hunt ci->branch_ratio_threshold = BRANCH_RATIO_THRESHOLD; 6499a968faSDavid Hunt ci->cd = malloc(ci->core_count * sizeof(struct core_details)); 6599a968faSDavid Hunt if (!ci->cd) { 6699a968faSDavid Hunt RTE_LOG(ERR, POWER_MANAGER, "Failed to allocate memory for core info."); 6799a968faSDavid Hunt return -1; 6899a968faSDavid Hunt } 6999a968faSDavid Hunt for (i = 0; i < ci->core_count; i++) { 7099a968faSDavid Hunt ci->cd[i].global_enabled_cpus = 1; 7199a968faSDavid Hunt ci->cd[i].oob_enabled = 0; 7299a968faSDavid Hunt ci->cd[i].msr_fd = 0; 7399a968faSDavid Hunt } 7499a968faSDavid Hunt printf("%d cores in system\n", ci->core_count); 7599a968faSDavid Hunt return 0; 7699a968faSDavid Hunt } 7799a968faSDavid Hunt 78d26c18c9SAlan Carew int 79d26c18c9SAlan Carew power_manager_init(void) 80d26c18c9SAlan Carew { 816453b928SDavid Hunt unsigned int i, num_cpus = 0, num_freqs = 0; 82d26c18c9SAlan Carew int ret = 0; 836453b928SDavid Hunt struct core_info *ci; 84c12ade20SDavid Hunt unsigned int max_core_num; 85d26c18c9SAlan Carew 866ff7b996SDavid Hunt rte_power_set_env(PM_ENV_NOT_SET); 876453b928SDavid Hunt 886453b928SDavid Hunt ci = get_core_info(); 896453b928SDavid Hunt if (!ci) { 906453b928SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 916453b928SDavid Hunt "Failed to get core info!\n"); 92d26c18c9SAlan Carew return -1; 93d26c18c9SAlan Carew } 946453b928SDavid Hunt 95751227a0SDavid Hunt if (ci->core_count > RTE_MAX_LCORE) 96751227a0SDavid Hunt max_core_num = RTE_MAX_LCORE; 97c12ade20SDavid Hunt else 98c12ade20SDavid Hunt max_core_num = ci->core_count; 99c12ade20SDavid Hunt 100c12ade20SDavid Hunt for (i = 0; i < max_core_num; i++) { 1016453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 1027f472f74SDavid Hunt if (rte_power_init(i) < 0) 1037f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1047f472f74SDavid Hunt "Unable to initialize power manager " 105d26c18c9SAlan Carew "for core %u\n", i); 1066453b928SDavid Hunt num_cpus++; 1076453b928SDavid Hunt num_freqs = rte_power_freqs(i, 1086453b928SDavid Hunt global_core_freq_info[i].freqs, 1097f472f74SDavid Hunt RTE_MAX_LCORE_FREQS); 1107f472f74SDavid Hunt if (num_freqs == 0) { 1117f472f74SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1127f472f74SDavid Hunt "Unable to get frequency list for core %u\n", 1137f472f74SDavid Hunt i); 1146453b928SDavid Hunt ci->cd[i].oob_enabled = 0; 115d26c18c9SAlan Carew ret = -1; 116d26c18c9SAlan Carew } 1177f472f74SDavid Hunt global_core_freq_info[i].num_freqs = num_freqs; 1186453b928SDavid Hunt 119d26c18c9SAlan Carew rte_spinlock_init(&global_core_freq_info[i].power_sl); 120d26c18c9SAlan Carew } 1216453b928SDavid Hunt if (ci->cd[i].oob_enabled) 1226453b928SDavid Hunt add_core_to_monitor(i); 1236453b928SDavid Hunt } 1246453b928SDavid Hunt RTE_LOG(INFO, POWER_MANAGER, "Managing %u cores out of %u available host cores\n", 1256453b928SDavid Hunt num_cpus, ci->core_count); 126d26c18c9SAlan Carew return ret; 127d26c18c9SAlan Carew 128d26c18c9SAlan Carew } 129d26c18c9SAlan Carew 130d26c18c9SAlan Carew uint32_t 131d26c18c9SAlan Carew power_manager_get_current_frequency(unsigned core_num) 132d26c18c9SAlan Carew { 133d26c18c9SAlan Carew uint32_t freq, index; 134d26c18c9SAlan Carew 135751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) { 136d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 137751227a0SDavid Hunt core_num, RTE_MAX_LCORE-1); 138d26c18c9SAlan Carew return -1; 139d26c18c9SAlan Carew } 1406453b928SDavid Hunt if (!(ci.cd[core_num].global_enabled_cpus)) 141d26c18c9SAlan Carew return 0; 142d26c18c9SAlan Carew 143d26c18c9SAlan Carew rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 144d26c18c9SAlan Carew index = rte_power_get_freq(core_num); 145d26c18c9SAlan Carew rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 146*3f1fc5f2SDavid Hunt if (index >= RTE_MAX_LCORE_FREQS) 147d26c18c9SAlan Carew freq = 0; 148d26c18c9SAlan Carew else 149d26c18c9SAlan Carew freq = global_core_freq_info[core_num].freqs[index]; 150d26c18c9SAlan Carew 151d26c18c9SAlan Carew return freq; 152d26c18c9SAlan Carew } 153d26c18c9SAlan Carew 154d26c18c9SAlan Carew int 155d26c18c9SAlan Carew power_manager_exit(void) 156d26c18c9SAlan Carew { 157d26c18c9SAlan Carew unsigned int i; 158d26c18c9SAlan Carew int ret = 0; 1596453b928SDavid Hunt struct core_info *ci; 160c12ade20SDavid Hunt unsigned int max_core_num; 161d26c18c9SAlan Carew 1626453b928SDavid Hunt ci = get_core_info(); 1636453b928SDavid Hunt if (!ci) { 1646453b928SDavid Hunt RTE_LOG(ERR, POWER_MANAGER, 1656453b928SDavid Hunt "Failed to get core info!\n"); 1666453b928SDavid Hunt return -1; 1676453b928SDavid Hunt } 1686453b928SDavid Hunt 169751227a0SDavid Hunt if (ci->core_count > RTE_MAX_LCORE) 170751227a0SDavid Hunt max_core_num = RTE_MAX_LCORE; 171c12ade20SDavid Hunt else 172c12ade20SDavid Hunt max_core_num = ci->core_count; 173c12ade20SDavid Hunt 174c12ade20SDavid Hunt for (i = 0; i < max_core_num; i++) { 1756453b928SDavid Hunt if (ci->cd[i].global_enabled_cpus) { 176d26c18c9SAlan Carew if (rte_power_exit(i) < 0) { 177d26c18c9SAlan Carew RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 178d26c18c9SAlan Carew "for core %u\n", i); 179d26c18c9SAlan Carew ret = -1; 180d26c18c9SAlan Carew } 1816453b928SDavid Hunt ci->cd[i].global_enabled_cpus = 0; 182d26c18c9SAlan Carew } 1836453b928SDavid Hunt remove_core_from_monitor(i); 1846453b928SDavid Hunt } 185d26c18c9SAlan Carew return ret; 186d26c18c9SAlan Carew } 187d26c18c9SAlan Carew 188d26c18c9SAlan Carew int 189d26c18c9SAlan Carew power_manager_scale_core_up(unsigned core_num) 190d26c18c9SAlan Carew { 191d26c18c9SAlan Carew int ret = 0; 192d26c18c9SAlan Carew 193d26c18c9SAlan Carew POWER_SCALE_CORE(up, core_num, ret); 194d26c18c9SAlan Carew return ret; 195d26c18c9SAlan Carew } 196d26c18c9SAlan Carew 197d26c18c9SAlan Carew int 198d26c18c9SAlan Carew power_manager_scale_core_down(unsigned core_num) 199d26c18c9SAlan Carew { 200d26c18c9SAlan Carew int ret = 0; 201d26c18c9SAlan Carew 202d26c18c9SAlan Carew POWER_SCALE_CORE(down, core_num, ret); 203d26c18c9SAlan Carew return ret; 204d26c18c9SAlan Carew } 205d26c18c9SAlan Carew 206d26c18c9SAlan Carew int 207d26c18c9SAlan Carew power_manager_scale_core_min(unsigned core_num) 208d26c18c9SAlan Carew { 209d26c18c9SAlan Carew int ret = 0; 210d26c18c9SAlan Carew 211d26c18c9SAlan Carew POWER_SCALE_CORE(min, core_num, ret); 212d26c18c9SAlan Carew return ret; 213d26c18c9SAlan Carew } 214d26c18c9SAlan Carew 215d26c18c9SAlan Carew int 216d26c18c9SAlan Carew power_manager_scale_core_max(unsigned core_num) 217d26c18c9SAlan Carew { 218d26c18c9SAlan Carew int ret = 0; 219d26c18c9SAlan Carew 220d26c18c9SAlan Carew POWER_SCALE_CORE(max, core_num, ret); 221d26c18c9SAlan Carew return ret; 222d26c18c9SAlan Carew } 223567997b9SDavid Hunt 224567997b9SDavid Hunt int 225567997b9SDavid Hunt power_manager_enable_turbo_core(unsigned int core_num) 226567997b9SDavid Hunt { 227567997b9SDavid Hunt int ret = 0; 228567997b9SDavid Hunt 229567997b9SDavid Hunt POWER_SCALE_CORE(enable_turbo, core_num, ret); 230567997b9SDavid Hunt return ret; 231567997b9SDavid Hunt } 232567997b9SDavid Hunt 233567997b9SDavid Hunt int 234567997b9SDavid Hunt power_manager_disable_turbo_core(unsigned int core_num) 235567997b9SDavid Hunt { 236567997b9SDavid Hunt int ret = 0; 237567997b9SDavid Hunt 238567997b9SDavid Hunt POWER_SCALE_CORE(disable_turbo, core_num, ret); 239567997b9SDavid Hunt return ret; 240567997b9SDavid Hunt } 2417f472f74SDavid Hunt 2427f472f74SDavid Hunt int 2437f472f74SDavid Hunt power_manager_scale_core_med(unsigned int core_num) 2447f472f74SDavid Hunt { 2457f472f74SDavid Hunt int ret = 0; 2466453b928SDavid Hunt struct core_info *ci; 2477f472f74SDavid Hunt 2486453b928SDavid Hunt ci = get_core_info(); 249751227a0SDavid Hunt if (core_num >= RTE_MAX_LCORE) 2507f472f74SDavid Hunt return -1; 2516453b928SDavid Hunt if (!(ci->cd[core_num].global_enabled_cpus)) 2527f472f74SDavid Hunt return -1; 2537f472f74SDavid Hunt rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 2547f472f74SDavid Hunt ret = rte_power_set_freq(core_num, 2557f472f74SDavid Hunt global_core_freq_info[core_num].num_freqs / 2); 2567f472f74SDavid Hunt rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 2577f472f74SDavid Hunt return ret; 2587f472f74SDavid Hunt } 259