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