1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <stdio.h> 6 #include <stdlib.h> 7 #include <stdint.h> 8 #include <inttypes.h> 9 #include <sys/un.h> 10 #include <fcntl.h> 11 #include <unistd.h> 12 #include <dirent.h> 13 #include <errno.h> 14 15 #include <sys/types.h> 16 17 #include <rte_log.h> 18 #include <rte_power.h> 19 #include <rte_spinlock.h> 20 21 #include "power_manager.h" 22 23 #define RTE_LOGTYPE_POWER_MANAGER RTE_LOGTYPE_USER1 24 25 #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \ 26 if (core_num >= POWER_MGR_MAX_CPUS) \ 27 return -1; \ 28 if (!(global_enabled_cpus & (1ULL << core_num))) \ 29 return -1; \ 30 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \ 31 ret = rte_power_freq_##DIRECTION(core_num); \ 32 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \ 33 } while (0) 34 35 #define POWER_SCALE_MASK(DIRECTION, core_mask, ret) do { \ 36 int i; \ 37 for (i = 0; core_mask; core_mask &= ~(1 << i++)) { \ 38 if ((core_mask >> i) & 1) { \ 39 if (!(global_enabled_cpus & (1ULL << i))) \ 40 continue; \ 41 rte_spinlock_lock(&global_core_freq_info[i].power_sl); \ 42 if (rte_power_freq_##DIRECTION(i) != 1) \ 43 ret = -1; \ 44 rte_spinlock_unlock(&global_core_freq_info[i].power_sl); \ 45 } \ 46 } \ 47 } while (0) 48 49 struct freq_info { 50 rte_spinlock_t power_sl; 51 uint32_t freqs[RTE_MAX_LCORE_FREQS]; 52 unsigned num_freqs; 53 } __rte_cache_aligned; 54 55 static struct freq_info global_core_freq_info[POWER_MGR_MAX_CPUS]; 56 57 static uint64_t global_enabled_cpus; 58 59 #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id" 60 61 static unsigned 62 set_host_cpus_mask(void) 63 { 64 char path[PATH_MAX]; 65 unsigned i; 66 unsigned num_cpus = 0; 67 68 for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 69 snprintf(path, sizeof(path), SYSFS_CPU_PATH, i); 70 if (access(path, F_OK) == 0) { 71 global_enabled_cpus |= 1ULL << i; 72 num_cpus++; 73 } else 74 return num_cpus; 75 } 76 return num_cpus; 77 } 78 79 int 80 power_manager_init(void) 81 { 82 unsigned int i, num_cpus, num_freqs; 83 uint64_t cpu_mask; 84 int ret = 0; 85 86 num_cpus = set_host_cpus_mask(); 87 if (num_cpus == 0) { 88 RTE_LOG(ERR, POWER_MANAGER, "Unable to detected host CPUs, please " 89 "ensure that sufficient privileges exist to inspect sysfs\n"); 90 return -1; 91 } 92 rte_power_set_env(PM_ENV_ACPI_CPUFREQ); 93 cpu_mask = global_enabled_cpus; 94 for (i = 0; cpu_mask; cpu_mask &= ~(1 << i++)) { 95 if (rte_power_init(i) < 0) 96 RTE_LOG(ERR, POWER_MANAGER, 97 "Unable to initialize power manager " 98 "for core %u\n", i); 99 num_freqs = rte_power_freqs(i, global_core_freq_info[i].freqs, 100 RTE_MAX_LCORE_FREQS); 101 if (num_freqs == 0) { 102 RTE_LOG(ERR, POWER_MANAGER, 103 "Unable to get frequency list for core %u\n", 104 i); 105 global_enabled_cpus &= ~(1 << i); 106 num_cpus--; 107 ret = -1; 108 } 109 global_core_freq_info[i].num_freqs = num_freqs; 110 rte_spinlock_init(&global_core_freq_info[i].power_sl); 111 } 112 RTE_LOG(INFO, POWER_MANAGER, "Detected %u host CPUs , enabled core mask:" 113 " 0x%"PRIx64"\n", num_cpus, global_enabled_cpus); 114 return ret; 115 116 } 117 118 uint32_t 119 power_manager_get_current_frequency(unsigned core_num) 120 { 121 uint32_t freq, index; 122 123 if (core_num >= POWER_MGR_MAX_CPUS) { 124 RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 125 core_num, POWER_MGR_MAX_CPUS-1); 126 return -1; 127 } 128 if (!(global_enabled_cpus & (1ULL << core_num))) 129 return 0; 130 131 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 132 index = rte_power_get_freq(core_num); 133 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 134 if (index >= POWER_MGR_MAX_CPUS) 135 freq = 0; 136 else 137 freq = global_core_freq_info[core_num].freqs[index]; 138 139 return freq; 140 } 141 142 int 143 power_manager_exit(void) 144 { 145 unsigned int i; 146 int ret = 0; 147 148 for (i = 0; global_enabled_cpus; global_enabled_cpus &= ~(1 << i++)) { 149 if (rte_power_exit(i) < 0) { 150 RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 151 "for core %u\n", i); 152 ret = -1; 153 } 154 } 155 global_enabled_cpus = 0; 156 return ret; 157 } 158 159 int 160 power_manager_scale_mask_up(uint64_t core_mask) 161 { 162 int ret = 0; 163 164 POWER_SCALE_MASK(up, core_mask, ret); 165 return ret; 166 } 167 168 int 169 power_manager_scale_mask_down(uint64_t core_mask) 170 { 171 int ret = 0; 172 173 POWER_SCALE_MASK(down, core_mask, ret); 174 return ret; 175 } 176 177 int 178 power_manager_scale_mask_min(uint64_t core_mask) 179 { 180 int ret = 0; 181 182 POWER_SCALE_MASK(min, core_mask, ret); 183 return ret; 184 } 185 186 int 187 power_manager_scale_mask_max(uint64_t core_mask) 188 { 189 int ret = 0; 190 191 POWER_SCALE_MASK(max, core_mask, ret); 192 return ret; 193 } 194 195 int 196 power_manager_enable_turbo_mask(uint64_t core_mask) 197 { 198 int ret = 0; 199 200 POWER_SCALE_MASK(enable_turbo, core_mask, ret); 201 return ret; 202 } 203 204 int 205 power_manager_disable_turbo_mask(uint64_t core_mask) 206 { 207 int ret = 0; 208 209 POWER_SCALE_MASK(disable_turbo, core_mask, ret); 210 return ret; 211 } 212 213 int 214 power_manager_scale_core_up(unsigned core_num) 215 { 216 int ret = 0; 217 218 POWER_SCALE_CORE(up, core_num, ret); 219 return ret; 220 } 221 222 int 223 power_manager_scale_core_down(unsigned core_num) 224 { 225 int ret = 0; 226 227 POWER_SCALE_CORE(down, core_num, ret); 228 return ret; 229 } 230 231 int 232 power_manager_scale_core_min(unsigned core_num) 233 { 234 int ret = 0; 235 236 POWER_SCALE_CORE(min, core_num, ret); 237 return ret; 238 } 239 240 int 241 power_manager_scale_core_max(unsigned core_num) 242 { 243 int ret = 0; 244 245 POWER_SCALE_CORE(max, core_num, ret); 246 return ret; 247 } 248 249 int 250 power_manager_enable_turbo_core(unsigned int core_num) 251 { 252 int ret = 0; 253 254 POWER_SCALE_CORE(enable_turbo, core_num, ret); 255 return ret; 256 } 257 258 int 259 power_manager_disable_turbo_core(unsigned int core_num) 260 { 261 int ret = 0; 262 263 POWER_SCALE_CORE(disable_turbo, core_num, ret); 264 return ret; 265 } 266 267 int 268 power_manager_scale_core_med(unsigned int core_num) 269 { 270 int ret = 0; 271 272 if (core_num >= POWER_MGR_MAX_CPUS) 273 return -1; 274 if (!(global_enabled_cpus & (1ULL << core_num))) 275 return -1; 276 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 277 ret = rte_power_set_freq(core_num, 278 global_core_freq_info[core_num].num_freqs / 2); 279 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 280 return ret; 281 } 282