1 /*- 2 * BSD LICENSE 3 * 4 * Copyright(c) 2010-2014 Intel Corporation. All rights reserved. 5 * All rights reserved. 6 * 7 * Redistribution and use in source and binary forms, with or without 8 * modification, are permitted provided that the following conditions 9 * are met: 10 * 11 * * Redistributions of source code must retain the above copyright 12 * notice, this list of conditions and the following disclaimer. 13 * * Redistributions in binary form must reproduce the above copyright 14 * notice, this list of conditions and the following disclaimer in 15 * the documentation and/or other materials provided with the 16 * distribution. 17 * * Neither the name of Intel Corporation nor the names of its 18 * contributors may be used to endorse or promote products derived 19 * from this software without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS 22 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT 23 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR 24 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT 25 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, 26 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT 27 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, 28 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 29 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT 30 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE 31 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. 32 */ 33 34 #include <stdio.h> 35 #include <stdlib.h> 36 #include <stdint.h> 37 #include <inttypes.h> 38 #include <sys/un.h> 39 #include <fcntl.h> 40 #include <unistd.h> 41 #include <dirent.h> 42 #include <errno.h> 43 44 #include <sys/types.h> 45 46 #include <rte_log.h> 47 #include <rte_power.h> 48 #include <rte_spinlock.h> 49 50 #include "power_manager.h" 51 52 #define RTE_LOGTYPE_POWER_MANAGER RTE_LOGTYPE_USER1 53 54 #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \ 55 if (core_num >= POWER_MGR_MAX_CPUS) \ 56 return -1; \ 57 if (!(global_enabled_cpus & (1ULL << core_num))) \ 58 return -1; \ 59 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \ 60 ret = rte_power_freq_##DIRECTION(core_num); \ 61 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \ 62 } while (0) 63 64 #define POWER_SCALE_MASK(DIRECTION, core_mask, ret) do { \ 65 int i; \ 66 for (i = 0; core_mask; core_mask &= ~(1 << i++)) { \ 67 if ((core_mask >> i) & 1) { \ 68 if (!(global_enabled_cpus & (1ULL << i))) \ 69 continue; \ 70 rte_spinlock_lock(&global_core_freq_info[i].power_sl); \ 71 if (rte_power_freq_##DIRECTION(i) != 1) \ 72 ret = -1; \ 73 rte_spinlock_unlock(&global_core_freq_info[i].power_sl); \ 74 } \ 75 } \ 76 } while (0) 77 78 struct freq_info { 79 rte_spinlock_t power_sl; 80 uint32_t freqs[RTE_MAX_LCORE_FREQS]; 81 unsigned num_freqs; 82 } __rte_cache_aligned; 83 84 static struct freq_info global_core_freq_info[POWER_MGR_MAX_CPUS]; 85 86 static uint64_t global_enabled_cpus; 87 88 #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id" 89 90 static unsigned 91 set_host_cpus_mask(void) 92 { 93 char path[PATH_MAX]; 94 unsigned i; 95 unsigned num_cpus = 0; 96 97 for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 98 snprintf(path, sizeof(path), SYSFS_CPU_PATH, i); 99 if (access(path, F_OK) == 0) { 100 global_enabled_cpus |= 1ULL << i; 101 num_cpus++; 102 } else 103 return num_cpus; 104 } 105 return num_cpus; 106 } 107 108 int 109 power_manager_init(void) 110 { 111 unsigned int i, num_cpus, num_freqs; 112 uint64_t cpu_mask; 113 int ret = 0; 114 115 num_cpus = set_host_cpus_mask(); 116 if (num_cpus == 0) { 117 RTE_LOG(ERR, POWER_MANAGER, "Unable to detected host CPUs, please " 118 "ensure that sufficient privileges exist to inspect sysfs\n"); 119 return -1; 120 } 121 rte_power_set_env(PM_ENV_ACPI_CPUFREQ); 122 cpu_mask = global_enabled_cpus; 123 for (i = 0; cpu_mask; cpu_mask &= ~(1 << i++)) { 124 if (rte_power_init(i) < 0) 125 RTE_LOG(ERR, POWER_MANAGER, 126 "Unable to initialize power manager " 127 "for core %u\n", i); 128 num_freqs = rte_power_freqs(i, global_core_freq_info[i].freqs, 129 RTE_MAX_LCORE_FREQS); 130 if (num_freqs == 0) { 131 RTE_LOG(ERR, POWER_MANAGER, 132 "Unable to get frequency list for core %u\n", 133 i); 134 global_enabled_cpus &= ~(1 << i); 135 num_cpus--; 136 ret = -1; 137 } 138 global_core_freq_info[i].num_freqs = num_freqs; 139 rte_spinlock_init(&global_core_freq_info[i].power_sl); 140 } 141 RTE_LOG(INFO, POWER_MANAGER, "Detected %u host CPUs , enabled core mask:" 142 " 0x%"PRIx64"\n", num_cpus, global_enabled_cpus); 143 return ret; 144 145 } 146 147 uint32_t 148 power_manager_get_current_frequency(unsigned core_num) 149 { 150 uint32_t freq, index; 151 152 if (core_num >= POWER_MGR_MAX_CPUS) { 153 RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 154 core_num, POWER_MGR_MAX_CPUS-1); 155 return -1; 156 } 157 if (!(global_enabled_cpus & (1ULL << core_num))) 158 return 0; 159 160 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 161 index = rte_power_get_freq(core_num); 162 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 163 if (index >= POWER_MGR_MAX_CPUS) 164 freq = 0; 165 else 166 freq = global_core_freq_info[core_num].freqs[index]; 167 168 return freq; 169 } 170 171 int 172 power_manager_exit(void) 173 { 174 unsigned int i; 175 int ret = 0; 176 177 for (i = 0; global_enabled_cpus; global_enabled_cpus &= ~(1 << i++)) { 178 if (rte_power_exit(i) < 0) { 179 RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 180 "for core %u\n", i); 181 ret = -1; 182 } 183 } 184 global_enabled_cpus = 0; 185 return ret; 186 } 187 188 int 189 power_manager_scale_mask_up(uint64_t core_mask) 190 { 191 int ret = 0; 192 193 POWER_SCALE_MASK(up, core_mask, ret); 194 return ret; 195 } 196 197 int 198 power_manager_scale_mask_down(uint64_t core_mask) 199 { 200 int ret = 0; 201 202 POWER_SCALE_MASK(down, core_mask, ret); 203 return ret; 204 } 205 206 int 207 power_manager_scale_mask_min(uint64_t core_mask) 208 { 209 int ret = 0; 210 211 POWER_SCALE_MASK(min, core_mask, ret); 212 return ret; 213 } 214 215 int 216 power_manager_scale_mask_max(uint64_t core_mask) 217 { 218 int ret = 0; 219 220 POWER_SCALE_MASK(max, core_mask, ret); 221 return ret; 222 } 223 224 int 225 power_manager_enable_turbo_mask(uint64_t core_mask) 226 { 227 int ret = 0; 228 229 POWER_SCALE_MASK(enable_turbo, core_mask, ret); 230 return ret; 231 } 232 233 int 234 power_manager_disable_turbo_mask(uint64_t core_mask) 235 { 236 int ret = 0; 237 238 POWER_SCALE_MASK(disable_turbo, core_mask, ret); 239 return ret; 240 } 241 242 int 243 power_manager_scale_core_up(unsigned core_num) 244 { 245 int ret = 0; 246 247 POWER_SCALE_CORE(up, core_num, ret); 248 return ret; 249 } 250 251 int 252 power_manager_scale_core_down(unsigned core_num) 253 { 254 int ret = 0; 255 256 POWER_SCALE_CORE(down, core_num, ret); 257 return ret; 258 } 259 260 int 261 power_manager_scale_core_min(unsigned core_num) 262 { 263 int ret = 0; 264 265 POWER_SCALE_CORE(min, core_num, ret); 266 return ret; 267 } 268 269 int 270 power_manager_scale_core_max(unsigned core_num) 271 { 272 int ret = 0; 273 274 POWER_SCALE_CORE(max, core_num, ret); 275 return ret; 276 } 277 278 int 279 power_manager_enable_turbo_core(unsigned int core_num) 280 { 281 int ret = 0; 282 283 POWER_SCALE_CORE(enable_turbo, core_num, ret); 284 return ret; 285 } 286 287 int 288 power_manager_disable_turbo_core(unsigned int core_num) 289 { 290 int ret = 0; 291 292 POWER_SCALE_CORE(disable_turbo, core_num, ret); 293 return ret; 294 } 295 296 int 297 power_manager_scale_core_med(unsigned int core_num) 298 { 299 int ret = 0; 300 301 if (core_num >= POWER_MGR_MAX_CPUS) 302 return -1; 303 if (!(global_enabled_cpus & (1ULL << core_num))) 304 return -1; 305 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 306 ret = rte_power_set_freq(core_num, 307 global_core_freq_info[core_num].num_freqs / 2); 308 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 309 return ret; 310 } 311