1 /* SPDX-License-Identifier: BSD-3-Clause 2 * Copyright(c) 2010-2014 Intel Corporation 3 * Copyright(c) 2023 AMD Corporation 4 */ 5 6 #include <rte_spinlock.h> 7 #include <rte_debug.h> 8 9 #include "rte_power_uncore.h" 10 #include "power_common.h" 11 12 static enum rte_uncore_power_mgmt_env global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET; 13 static struct rte_power_uncore_ops *global_uncore_ops; 14 15 static rte_spinlock_t global_env_cfg_lock = RTE_SPINLOCK_INITIALIZER; 16 static RTE_TAILQ_HEAD(, rte_power_uncore_ops) uncore_ops_list = 17 TAILQ_HEAD_INITIALIZER(uncore_ops_list); 18 19 const char *uncore_env_str[] = { 20 "not set", 21 "auto-detect", 22 "intel-uncore", 23 "amd-hsmp" 24 }; 25 26 /* register the ops struct in rte_power_uncore_ops, return 0 on success. */ 27 int 28 rte_power_register_uncore_ops(struct rte_power_uncore_ops *driver_ops) 29 { 30 if (!driver_ops->init || !driver_ops->exit || !driver_ops->get_num_pkgs || 31 !driver_ops->get_num_dies || !driver_ops->get_num_freqs || 32 !driver_ops->get_avail_freqs || !driver_ops->get_freq || 33 !driver_ops->set_freq || !driver_ops->freq_max || 34 !driver_ops->freq_min) { 35 POWER_LOG(ERR, "Missing callbacks while registering power ops"); 36 return -1; 37 } 38 39 if (driver_ops->cb) 40 driver_ops->cb(); 41 42 TAILQ_INSERT_TAIL(&uncore_ops_list, driver_ops, next); 43 44 return 0; 45 } 46 47 int 48 rte_power_set_uncore_env(enum rte_uncore_power_mgmt_env env) 49 { 50 int ret = -1; 51 struct rte_power_uncore_ops *ops; 52 53 rte_spinlock_lock(&global_env_cfg_lock); 54 55 if (global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) { 56 POWER_LOG(ERR, "Uncore Power Management Env already set."); 57 goto out; 58 } 59 60 if (env == RTE_UNCORE_PM_ENV_AUTO_DETECT) 61 /* Currently only intel_uncore is supported. 62 * This will be extended with auto-detection support 63 * for multiple uncore implementations. 64 */ 65 env = RTE_UNCORE_PM_ENV_INTEL_UNCORE; 66 67 if (env <= RTE_DIM(uncore_env_str)) { 68 RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next) 69 if (strncmp(ops->name, uncore_env_str[env], 70 RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) { 71 global_uncore_env = env; 72 global_uncore_ops = ops; 73 ret = 0; 74 goto out; 75 } 76 POWER_LOG(ERR, "Power Management (%s) not supported", 77 uncore_env_str[env]); 78 } else 79 POWER_LOG(ERR, "Invalid Power Management Environment"); 80 81 out: 82 rte_spinlock_unlock(&global_env_cfg_lock); 83 return ret; 84 } 85 86 void 87 rte_power_unset_uncore_env(void) 88 { 89 rte_spinlock_lock(&global_env_cfg_lock); 90 global_uncore_env = RTE_UNCORE_PM_ENV_NOT_SET; 91 rte_spinlock_unlock(&global_env_cfg_lock); 92 } 93 94 enum rte_uncore_power_mgmt_env 95 rte_power_get_uncore_env(void) 96 { 97 return global_uncore_env; 98 } 99 100 int 101 rte_power_uncore_init(unsigned int pkg, unsigned int die) 102 { 103 int ret = -1; 104 struct rte_power_uncore_ops *ops; 105 uint8_t env; 106 107 if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) && 108 (global_uncore_env != RTE_UNCORE_PM_ENV_AUTO_DETECT)) 109 return global_uncore_ops->init(pkg, die); 110 111 /* Auto Detect Environment */ 112 RTE_TAILQ_FOREACH(ops, &uncore_ops_list, next) 113 if (ops) { 114 POWER_LOG(INFO, 115 "Attempting to initialise %s power management...", 116 ops->name); 117 ret = ops->init(pkg, die); 118 if (ret == 0) { 119 for (env = 0; env < RTE_DIM(uncore_env_str); env++) 120 if (strncmp(ops->name, uncore_env_str[env], 121 RTE_POWER_UNCORE_DRIVER_NAMESZ) == 0) { 122 rte_power_set_uncore_env(env); 123 goto out; 124 } 125 } 126 } 127 out: 128 return ret; 129 } 130 131 int 132 rte_power_uncore_exit(unsigned int pkg, unsigned int die) 133 { 134 if ((global_uncore_env != RTE_UNCORE_PM_ENV_NOT_SET) && 135 global_uncore_ops) 136 return global_uncore_ops->exit(pkg, die); 137 138 POWER_LOG(ERR, 139 "Uncore Env has not been set, unable to exit gracefully"); 140 141 return -1; 142 } 143 144 uint32_t 145 rte_power_get_uncore_freq(unsigned int pkg, unsigned int die) 146 { 147 RTE_ASSERT(global_uncore_ops != NULL); 148 return global_uncore_ops->get_freq(pkg, die); 149 } 150 151 int 152 rte_power_set_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index) 153 { 154 RTE_ASSERT(global_uncore_ops != NULL); 155 return global_uncore_ops->set_freq(pkg, die, index); 156 } 157 158 int 159 rte_power_uncore_freq_max(unsigned int pkg, unsigned int die) 160 { 161 RTE_ASSERT(global_uncore_ops != NULL); 162 return global_uncore_ops->freq_max(pkg, die); 163 } 164 165 int 166 rte_power_uncore_freq_min(unsigned int pkg, unsigned int die) 167 { 168 RTE_ASSERT(global_uncore_ops != NULL); 169 return global_uncore_ops->freq_min(pkg, die); 170 } 171 172 int 173 rte_power_uncore_freqs(unsigned int pkg, unsigned int die, 174 uint32_t *freqs, uint32_t num) 175 { 176 RTE_ASSERT(global_uncore_ops != NULL); 177 return global_uncore_ops->get_avail_freqs(pkg, die, freqs, num); 178 } 179 180 int 181 rte_power_uncore_get_num_freqs(unsigned int pkg, unsigned int die) 182 { 183 RTE_ASSERT(global_uncore_ops != NULL); 184 return global_uncore_ops->get_num_freqs(pkg, die); 185 } 186 187 unsigned int 188 rte_power_uncore_get_num_pkgs(void) 189 { 190 RTE_ASSERT(global_uncore_ops != NULL); 191 return global_uncore_ops->get_num_pkgs(); 192 } 193 194 unsigned int 195 rte_power_uncore_get_num_dies(unsigned int pkg) 196 { 197 RTE_ASSERT(global_uncore_ops != NULL); 198 return global_uncore_ops->get_num_dies(pkg); 199 } 200