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_config.h> 47 #include <rte_log.h> 48 #include <rte_power.h> 49 #include <rte_spinlock.h> 50 51 #include "power_manager.h" 52 53 #define RTE_LOGTYPE_POWER_MANAGER RTE_LOGTYPE_USER1 54 55 #define POWER_SCALE_CORE(DIRECTION, core_num , ret) do { \ 56 if (core_num >= POWER_MGR_MAX_CPUS) \ 57 return -1; \ 58 if (!(global_enabled_cpus & (1ULL << core_num))) \ 59 return -1; \ 60 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); \ 61 ret = rte_power_freq_##DIRECTION(core_num); \ 62 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); \ 63 } while (0) 64 65 #define POWER_SCALE_MASK(DIRECTION, core_mask, ret) do { \ 66 int i; \ 67 for (i = 0; core_mask; core_mask &= ~(1 << i++)) { \ 68 if ((core_mask >> i) & 1) { \ 69 if (!(global_enabled_cpus & (1ULL << i))) \ 70 continue; \ 71 rte_spinlock_lock(&global_core_freq_info[i].power_sl); \ 72 if (rte_power_freq_##DIRECTION(i) != 1) \ 73 ret = -1; \ 74 rte_spinlock_unlock(&global_core_freq_info[i].power_sl); \ 75 } \ 76 } \ 77 } while (0) 78 79 struct freq_info { 80 rte_spinlock_t power_sl; 81 uint32_t freqs[RTE_MAX_LCORE_FREQS]; 82 unsigned num_freqs; 83 } __rte_cache_aligned; 84 85 static struct freq_info global_core_freq_info[POWER_MGR_MAX_CPUS]; 86 87 static uint64_t global_enabled_cpus; 88 89 #define SYSFS_CPU_PATH "/sys/devices/system/cpu/cpu%u/topology/core_id" 90 91 static unsigned 92 set_host_cpus_mask(void) 93 { 94 char path[PATH_MAX]; 95 unsigned i; 96 unsigned num_cpus = 0; 97 98 for (i = 0; i < POWER_MGR_MAX_CPUS; i++) { 99 snprintf(path, sizeof(path), SYSFS_CPU_PATH, i); 100 if (access(path, F_OK) == 0) { 101 global_enabled_cpus |= 1ULL << i; 102 num_cpus++; 103 } else 104 return num_cpus; 105 } 106 return num_cpus; 107 } 108 109 int 110 power_manager_init(void) 111 { 112 unsigned i, num_cpus; 113 uint64_t cpu_mask; 114 int ret = 0; 115 116 num_cpus = set_host_cpus_mask(); 117 if (num_cpus == 0) { 118 RTE_LOG(ERR, POWER_MANAGER, "Unable to detected host CPUs, please " 119 "ensure that sufficient privileges exist to inspect sysfs\n"); 120 return -1; 121 } 122 rte_power_set_env(PM_ENV_ACPI_CPUFREQ); 123 cpu_mask = global_enabled_cpus; 124 for (i = 0; cpu_mask; cpu_mask &= ~(1 << i++)) { 125 if (rte_power_init(i) < 0 || rte_power_freqs(i, 126 global_core_freq_info[i].freqs, 127 RTE_MAX_LCORE_FREQS) == 0) { 128 RTE_LOG(ERR, POWER_MANAGER, "Unable to initialize power manager " 129 "for core %u\n", i); 130 global_enabled_cpus &= ~(1 << i); 131 num_cpus--; 132 ret = -1; 133 } 134 rte_spinlock_init(&global_core_freq_info[i].power_sl); 135 } 136 RTE_LOG(INFO, POWER_MANAGER, "Detected %u host CPUs , enabled core mask:" 137 " 0x%"PRIx64"\n", num_cpus, global_enabled_cpus); 138 return ret; 139 140 } 141 142 uint32_t 143 power_manager_get_current_frequency(unsigned core_num) 144 { 145 uint32_t freq, index; 146 147 if (core_num >= POWER_MGR_MAX_CPUS) { 148 RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 149 core_num, POWER_MGR_MAX_CPUS-1); 150 return -1; 151 } 152 if (!(global_enabled_cpus & (1ULL << core_num))) 153 return 0; 154 155 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 156 index = rte_power_get_freq(core_num); 157 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 158 if (index >= POWER_MGR_MAX_CPUS) 159 freq = 0; 160 else 161 freq = global_core_freq_info[core_num].freqs[index]; 162 163 return freq; 164 } 165 166 int 167 power_manager_exit(void) 168 { 169 unsigned int i; 170 int ret = 0; 171 172 for (i = 0; global_enabled_cpus; global_enabled_cpus &= ~(1 << i++)) { 173 if (rte_power_exit(i) < 0) { 174 RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 175 "for core %u\n", i); 176 ret = -1; 177 } 178 } 179 global_enabled_cpus = 0; 180 return ret; 181 } 182 183 int 184 power_manager_scale_mask_up(uint64_t core_mask) 185 { 186 int ret = 0; 187 188 POWER_SCALE_MASK(up, core_mask, ret); 189 return ret; 190 } 191 192 int 193 power_manager_scale_mask_down(uint64_t core_mask) 194 { 195 int ret = 0; 196 197 POWER_SCALE_MASK(down, core_mask, ret); 198 return ret; 199 } 200 201 int 202 power_manager_scale_mask_min(uint64_t core_mask) 203 { 204 int ret = 0; 205 206 POWER_SCALE_MASK(min, core_mask, ret); 207 return ret; 208 } 209 210 int 211 power_manager_scale_mask_max(uint64_t core_mask) 212 { 213 int ret = 0; 214 215 POWER_SCALE_MASK(max, core_mask, ret); 216 return ret; 217 } 218 219 int 220 power_manager_scale_core_up(unsigned core_num) 221 { 222 int ret = 0; 223 224 POWER_SCALE_CORE(up, core_num, ret); 225 return ret; 226 } 227 228 int 229 power_manager_scale_core_down(unsigned core_num) 230 { 231 int ret = 0; 232 233 POWER_SCALE_CORE(down, core_num, ret); 234 return ret; 235 } 236 237 int 238 power_manager_scale_core_min(unsigned core_num) 239 { 240 int ret = 0; 241 242 POWER_SCALE_CORE(min, core_num, ret); 243 return ret; 244 } 245 246 int 247 power_manager_scale_core_max(unsigned core_num) 248 { 249 int ret = 0; 250 251 POWER_SCALE_CORE(max, core_num, ret); 252 return ret; 253 } 254