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 i, num_cpus; 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 || rte_power_freqs(i, 125 global_core_freq_info[i].freqs, 126 RTE_MAX_LCORE_FREQS) == 0) { 127 RTE_LOG(ERR, POWER_MANAGER, "Unable to initialize power manager " 128 "for core %u\n", i); 129 global_enabled_cpus &= ~(1 << i); 130 num_cpus--; 131 ret = -1; 132 } 133 rte_spinlock_init(&global_core_freq_info[i].power_sl); 134 } 135 RTE_LOG(INFO, POWER_MANAGER, "Detected %u host CPUs , enabled core mask:" 136 " 0x%"PRIx64"\n", num_cpus, global_enabled_cpus); 137 return ret; 138 139 } 140 141 uint32_t 142 power_manager_get_current_frequency(unsigned core_num) 143 { 144 uint32_t freq, index; 145 146 if (core_num >= POWER_MGR_MAX_CPUS) { 147 RTE_LOG(ERR, POWER_MANAGER, "Core(%u) is out of range 0...%d\n", 148 core_num, POWER_MGR_MAX_CPUS-1); 149 return -1; 150 } 151 if (!(global_enabled_cpus & (1ULL << core_num))) 152 return 0; 153 154 rte_spinlock_lock(&global_core_freq_info[core_num].power_sl); 155 index = rte_power_get_freq(core_num); 156 rte_spinlock_unlock(&global_core_freq_info[core_num].power_sl); 157 if (index >= POWER_MGR_MAX_CPUS) 158 freq = 0; 159 else 160 freq = global_core_freq_info[core_num].freqs[index]; 161 162 return freq; 163 } 164 165 int 166 power_manager_exit(void) 167 { 168 unsigned int i; 169 int ret = 0; 170 171 for (i = 0; global_enabled_cpus; global_enabled_cpus &= ~(1 << i++)) { 172 if (rte_power_exit(i) < 0) { 173 RTE_LOG(ERR, POWER_MANAGER, "Unable to shutdown power manager " 174 "for core %u\n", i); 175 ret = -1; 176 } 177 } 178 global_enabled_cpus = 0; 179 return ret; 180 } 181 182 int 183 power_manager_scale_mask_up(uint64_t core_mask) 184 { 185 int ret = 0; 186 187 POWER_SCALE_MASK(up, core_mask, ret); 188 return ret; 189 } 190 191 int 192 power_manager_scale_mask_down(uint64_t core_mask) 193 { 194 int ret = 0; 195 196 POWER_SCALE_MASK(down, core_mask, ret); 197 return ret; 198 } 199 200 int 201 power_manager_scale_mask_min(uint64_t core_mask) 202 { 203 int ret = 0; 204 205 POWER_SCALE_MASK(min, core_mask, ret); 206 return ret; 207 } 208 209 int 210 power_manager_scale_mask_max(uint64_t core_mask) 211 { 212 int ret = 0; 213 214 POWER_SCALE_MASK(max, core_mask, ret); 215 return ret; 216 } 217 218 int 219 power_manager_scale_core_up(unsigned core_num) 220 { 221 int ret = 0; 222 223 POWER_SCALE_CORE(up, core_num, ret); 224 return ret; 225 } 226 227 int 228 power_manager_scale_core_down(unsigned core_num) 229 { 230 int ret = 0; 231 232 POWER_SCALE_CORE(down, core_num, ret); 233 return ret; 234 } 235 236 int 237 power_manager_scale_core_min(unsigned core_num) 238 { 239 int ret = 0; 240 241 POWER_SCALE_CORE(min, core_num, ret); 242 return ret; 243 } 244 245 int 246 power_manager_scale_core_max(unsigned core_num) 247 { 248 int ret = 0; 249 250 POWER_SCALE_CORE(max, core_num, ret); 251 return ret; 252 } 253