1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 */ 4 5 #include <rte_spinlock.h> 6 #include <rte_debug.h> 7 8 #include "rte_power_cpufreq.h" 9 #include "power_common.h" 10 11 static enum power_management_env global_default_env = PM_ENV_NOT_SET; 12 static struct rte_power_cpufreq_ops *global_cpufreq_ops; 13 14 static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER; 15 static RTE_TAILQ_HEAD(, rte_power_cpufreq_ops) cpufreq_ops_list = 16 TAILQ_HEAD_INITIALIZER(cpufreq_ops_list); 17 18 const char *power_env_str[] = { 19 "not set", 20 "acpi", 21 "kvm-vm", 22 "intel-pstate", 23 "cppc", 24 "amd-pstate" 25 }; 26 27 /* register the ops struct in rte_power_cpufreq_ops, return 0 on success. */ 28 int 29 rte_power_register_cpufreq_ops(struct rte_power_cpufreq_ops *driver_ops) 30 { 31 if (!driver_ops->init || !driver_ops->exit || 32 !driver_ops->check_env_support || !driver_ops->get_avail_freqs || 33 !driver_ops->get_freq || !driver_ops->set_freq || 34 !driver_ops->freq_up || !driver_ops->freq_down || 35 !driver_ops->freq_max || !driver_ops->freq_min || 36 !driver_ops->turbo_status || !driver_ops->enable_turbo || 37 !driver_ops->disable_turbo || !driver_ops->get_caps) { 38 POWER_LOG(ERR, "Missing callbacks while registering cpufreq ops"); 39 return -1; 40 } 41 42 TAILQ_INSERT_TAIL(&cpufreq_ops_list, driver_ops, next); 43 44 return 0; 45 } 46 47 int 48 rte_power_check_env_supported(enum power_management_env env) 49 { 50 struct rte_power_cpufreq_ops *ops; 51 52 if (env >= RTE_DIM(power_env_str)) 53 return 0; 54 55 RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next) 56 if (strncmp(ops->name, power_env_str[env], 57 RTE_POWER_DRIVER_NAMESZ) == 0) 58 return ops->check_env_support(); 59 60 return 0; 61 } 62 63 int 64 rte_power_set_env(enum power_management_env env) 65 { 66 struct rte_power_cpufreq_ops *ops; 67 int ret = -1; 68 69 rte_spinlock_lock(&global_env_cfg_lock); 70 71 if (global_default_env != PM_ENV_NOT_SET) { 72 POWER_LOG(ERR, "Power Management Environment already set."); 73 goto out; 74 } 75 76 RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next) 77 if (strncmp(ops->name, power_env_str[env], 78 RTE_POWER_DRIVER_NAMESZ) == 0) { 79 global_cpufreq_ops = ops; 80 global_default_env = env; 81 ret = 0; 82 goto out; 83 } 84 85 POWER_LOG(ERR, "Invalid Power Management Environment(%d) set", 86 env); 87 out: 88 rte_spinlock_unlock(&global_env_cfg_lock); 89 return ret; 90 } 91 92 void 93 rte_power_unset_env(void) 94 { 95 rte_spinlock_lock(&global_env_cfg_lock); 96 global_default_env = PM_ENV_NOT_SET; 97 global_cpufreq_ops = NULL; 98 rte_spinlock_unlock(&global_env_cfg_lock); 99 } 100 101 enum power_management_env 102 rte_power_get_env(void) { 103 return global_default_env; 104 } 105 106 int 107 rte_power_init(unsigned int lcore_id) 108 { 109 struct rte_power_cpufreq_ops *ops; 110 uint8_t env; 111 112 if (global_default_env != PM_ENV_NOT_SET) 113 return global_cpufreq_ops->init(lcore_id); 114 115 POWER_LOG(INFO, "Env isn't set yet!"); 116 117 /* Auto detect Environment */ 118 RTE_TAILQ_FOREACH(ops, &cpufreq_ops_list, next) { 119 POWER_LOG(INFO, 120 "Attempting to initialise %s cpufreq power management...", 121 ops->name); 122 for (env = 0; env < RTE_DIM(power_env_str); env++) { 123 if ((strncmp(ops->name, power_env_str[env], 124 RTE_POWER_DRIVER_NAMESZ) == 0) && 125 (ops->init(lcore_id) == 0)) { 126 rte_power_set_env(env); 127 return 0; 128 } 129 } 130 } 131 132 POWER_LOG(ERR, 133 "Unable to set Power Management Environment for lcore %u", 134 lcore_id); 135 136 return -1; 137 } 138 139 int 140 rte_power_exit(unsigned int lcore_id) 141 { 142 if (global_default_env != PM_ENV_NOT_SET) 143 return global_cpufreq_ops->exit(lcore_id); 144 145 POWER_LOG(ERR, 146 "Environment has not been set, unable to exit gracefully"); 147 148 return -1; 149 } 150 151 uint32_t 152 rte_power_freqs(unsigned int lcore_id, uint32_t *freqs, uint32_t n) 153 { 154 RTE_ASSERT(global_cpufreq_ops != NULL); 155 return global_cpufreq_ops->get_avail_freqs(lcore_id, freqs, n); 156 } 157 158 uint32_t 159 rte_power_get_freq(unsigned int lcore_id) 160 { 161 RTE_ASSERT(global_cpufreq_ops != NULL); 162 return global_cpufreq_ops->get_freq(lcore_id); 163 } 164 165 uint32_t 166 rte_power_set_freq(unsigned int lcore_id, uint32_t index) 167 { 168 RTE_ASSERT(global_cpufreq_ops != NULL); 169 return global_cpufreq_ops->set_freq(lcore_id, index); 170 } 171 172 int 173 rte_power_freq_up(unsigned int lcore_id) 174 { 175 RTE_ASSERT(global_cpufreq_ops != NULL); 176 return global_cpufreq_ops->freq_up(lcore_id); 177 } 178 179 int 180 rte_power_freq_down(unsigned int lcore_id) 181 { 182 RTE_ASSERT(global_cpufreq_ops != NULL); 183 return global_cpufreq_ops->freq_down(lcore_id); 184 } 185 186 int 187 rte_power_freq_max(unsigned int lcore_id) 188 { 189 RTE_ASSERT(global_cpufreq_ops != NULL); 190 return global_cpufreq_ops->freq_max(lcore_id); 191 } 192 193 int 194 rte_power_freq_min(unsigned int lcore_id) 195 { 196 RTE_ASSERT(global_cpufreq_ops != NULL); 197 return global_cpufreq_ops->freq_min(lcore_id); 198 } 199 200 int 201 rte_power_turbo_status(unsigned int lcore_id) 202 { 203 RTE_ASSERT(global_cpufreq_ops != NULL); 204 return global_cpufreq_ops->turbo_status(lcore_id); 205 } 206 207 int 208 rte_power_freq_enable_turbo(unsigned int lcore_id) 209 { 210 RTE_ASSERT(global_cpufreq_ops != NULL); 211 return global_cpufreq_ops->enable_turbo(lcore_id); 212 } 213 214 int 215 rte_power_freq_disable_turbo(unsigned int lcore_id) 216 { 217 RTE_ASSERT(global_cpufreq_ops != NULL); 218 return global_cpufreq_ops->disable_turbo(lcore_id); 219 } 220 221 int 222 rte_power_get_capabilities(unsigned int lcore_id, 223 struct rte_power_core_capabilities *caps) 224 { 225 RTE_ASSERT(global_cpufreq_ops != NULL); 226 return global_cpufreq_ops->get_caps(lcore_id, caps); 227 } 228