1*da4d64d0SSivaprasad Tummala /* SPDX-License-Identifier: BSD-3-Clause 2*da4d64d0SSivaprasad Tummala * Copyright(c) 2024 Advanced Micro Devices, Inc. 3*da4d64d0SSivaprasad Tummala */ 4*da4d64d0SSivaprasad Tummala 5*da4d64d0SSivaprasad Tummala #include <errno.h> 6*da4d64d0SSivaprasad Tummala #include <dirent.h> 7*da4d64d0SSivaprasad Tummala #include <fnmatch.h> 8*da4d64d0SSivaprasad Tummala 9*da4d64d0SSivaprasad Tummala #include <rte_memcpy.h> 10*da4d64d0SSivaprasad Tummala 11*da4d64d0SSivaprasad Tummala #include "amd_uncore.h" 12*da4d64d0SSivaprasad Tummala #include "power_common.h" 13*da4d64d0SSivaprasad Tummala #include "e_smi/e_smi.h" 14*da4d64d0SSivaprasad Tummala 15*da4d64d0SSivaprasad Tummala #define MAX_NUMA_DIE 8 16*da4d64d0SSivaprasad Tummala 17*da4d64d0SSivaprasad Tummala struct __rte_cache_aligned uncore_power_info { 18*da4d64d0SSivaprasad Tummala unsigned int die; /* Core die id */ 19*da4d64d0SSivaprasad Tummala unsigned int pkg; /* Package id */ 20*da4d64d0SSivaprasad Tummala uint32_t freqs[RTE_MAX_UNCORE_FREQS]; /* Frequency array */ 21*da4d64d0SSivaprasad Tummala uint32_t nb_freqs; /* Number of available freqs */ 22*da4d64d0SSivaprasad Tummala uint32_t curr_idx; /* Freq index in freqs array */ 23*da4d64d0SSivaprasad Tummala uint32_t max_freq; /* System max uncore freq */ 24*da4d64d0SSivaprasad Tummala uint32_t min_freq; /* System min uncore freq */ 25*da4d64d0SSivaprasad Tummala }; 26*da4d64d0SSivaprasad Tummala 27*da4d64d0SSivaprasad Tummala static struct uncore_power_info uncore_info[RTE_MAX_NUMA_NODES][MAX_NUMA_DIE]; 28*da4d64d0SSivaprasad Tummala static int esmi_initialized; 29*da4d64d0SSivaprasad Tummala static unsigned int hsmp_proto_ver; 30*da4d64d0SSivaprasad Tummala 31*da4d64d0SSivaprasad Tummala static int 32*da4d64d0SSivaprasad Tummala set_uncore_freq_internal(struct uncore_power_info *ui, uint32_t idx) 33*da4d64d0SSivaprasad Tummala { 34*da4d64d0SSivaprasad Tummala int ret; 35*da4d64d0SSivaprasad Tummala 36*da4d64d0SSivaprasad Tummala if (idx >= RTE_MAX_UNCORE_FREQS || idx >= ui->nb_freqs) { 37*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "Invalid uncore frequency index %u, which " 38*da4d64d0SSivaprasad Tummala "should be less than %u", idx, ui->nb_freqs); 39*da4d64d0SSivaprasad Tummala return -1; 40*da4d64d0SSivaprasad Tummala } 41*da4d64d0SSivaprasad Tummala 42*da4d64d0SSivaprasad Tummala ret = esmi_apb_disable(ui->pkg, idx); 43*da4d64d0SSivaprasad Tummala if (ret != ESMI_SUCCESS) { 44*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "DF P-state '%u' set failed for pkg %02u", 45*da4d64d0SSivaprasad Tummala idx, ui->pkg); 46*da4d64d0SSivaprasad Tummala return -1; 47*da4d64d0SSivaprasad Tummala } 48*da4d64d0SSivaprasad Tummala 49*da4d64d0SSivaprasad Tummala POWER_DEBUG_LOG("DF P-state '%u' to be set for pkg %02u die %02u", 50*da4d64d0SSivaprasad Tummala idx, ui->pkg, ui->die); 51*da4d64d0SSivaprasad Tummala 52*da4d64d0SSivaprasad Tummala /* write the minimum value first if the target freq is less than current max */ 53*da4d64d0SSivaprasad Tummala ui->curr_idx = idx; 54*da4d64d0SSivaprasad Tummala 55*da4d64d0SSivaprasad Tummala return 0; 56*da4d64d0SSivaprasad Tummala } 57*da4d64d0SSivaprasad Tummala 58*da4d64d0SSivaprasad Tummala static int 59*da4d64d0SSivaprasad Tummala power_init_for_setting_uncore_freq(struct uncore_power_info *ui) 60*da4d64d0SSivaprasad Tummala { 61*da4d64d0SSivaprasad Tummala switch (hsmp_proto_ver) { 62*da4d64d0SSivaprasad Tummala case HSMP_PROTO_VER5: 63*da4d64d0SSivaprasad Tummala ui->max_freq = 1800000; /* Hz */ 64*da4d64d0SSivaprasad Tummala ui->min_freq = 1200000; /* Hz */ 65*da4d64d0SSivaprasad Tummala break; 66*da4d64d0SSivaprasad Tummala case HSMP_PROTO_VER2: 67*da4d64d0SSivaprasad Tummala default: 68*da4d64d0SSivaprasad Tummala ui->max_freq = 1600000; /* Hz */ 69*da4d64d0SSivaprasad Tummala ui->min_freq = 1200000; /* Hz */ 70*da4d64d0SSivaprasad Tummala } 71*da4d64d0SSivaprasad Tummala 72*da4d64d0SSivaprasad Tummala return 0; 73*da4d64d0SSivaprasad Tummala } 74*da4d64d0SSivaprasad Tummala 75*da4d64d0SSivaprasad Tummala /* 76*da4d64d0SSivaprasad Tummala * Get the available uncore frequencies of the specific die. 77*da4d64d0SSivaprasad Tummala */ 78*da4d64d0SSivaprasad Tummala static int 79*da4d64d0SSivaprasad Tummala power_get_available_uncore_freqs(struct uncore_power_info *ui) 80*da4d64d0SSivaprasad Tummala { 81*da4d64d0SSivaprasad Tummala ui->nb_freqs = 3; 82*da4d64d0SSivaprasad Tummala if (ui->nb_freqs >= RTE_MAX_UNCORE_FREQS) { 83*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "Too many available uncore frequencies: %d", 84*da4d64d0SSivaprasad Tummala ui->nb_freqs); 85*da4d64d0SSivaprasad Tummala return -1; 86*da4d64d0SSivaprasad Tummala } 87*da4d64d0SSivaprasad Tummala 88*da4d64d0SSivaprasad Tummala /* Generate the uncore freq bucket array. */ 89*da4d64d0SSivaprasad Tummala switch (hsmp_proto_ver) { 90*da4d64d0SSivaprasad Tummala case HSMP_PROTO_VER5: 91*da4d64d0SSivaprasad Tummala ui->freqs[0] = 1800000; 92*da4d64d0SSivaprasad Tummala ui->freqs[1] = 1440000; 93*da4d64d0SSivaprasad Tummala ui->freqs[2] = 1200000; 94*da4d64d0SSivaprasad Tummala break; 95*da4d64d0SSivaprasad Tummala case HSMP_PROTO_VER2: 96*da4d64d0SSivaprasad Tummala default: 97*da4d64d0SSivaprasad Tummala ui->freqs[0] = 1600000; 98*da4d64d0SSivaprasad Tummala ui->freqs[1] = 1333000; 99*da4d64d0SSivaprasad Tummala ui->freqs[2] = 1200000; 100*da4d64d0SSivaprasad Tummala } 101*da4d64d0SSivaprasad Tummala 102*da4d64d0SSivaprasad Tummala POWER_DEBUG_LOG("%d frequency(s) of pkg %02u die %02u are available", 103*da4d64d0SSivaprasad Tummala ui->num_uncore_freqs, ui->pkg, ui->die); 104*da4d64d0SSivaprasad Tummala 105*da4d64d0SSivaprasad Tummala return 0; 106*da4d64d0SSivaprasad Tummala } 107*da4d64d0SSivaprasad Tummala 108*da4d64d0SSivaprasad Tummala static int 109*da4d64d0SSivaprasad Tummala check_pkg_die_values(unsigned int pkg, unsigned int die) 110*da4d64d0SSivaprasad Tummala { 111*da4d64d0SSivaprasad Tummala unsigned int max_pkgs, max_dies; 112*da4d64d0SSivaprasad Tummala max_pkgs = power_amd_uncore_get_num_pkgs(); 113*da4d64d0SSivaprasad Tummala if (max_pkgs == 0) 114*da4d64d0SSivaprasad Tummala return -1; 115*da4d64d0SSivaprasad Tummala if (pkg >= max_pkgs) { 116*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "Package number %02u can not exceed %u", 117*da4d64d0SSivaprasad Tummala pkg, max_pkgs); 118*da4d64d0SSivaprasad Tummala return -1; 119*da4d64d0SSivaprasad Tummala } 120*da4d64d0SSivaprasad Tummala 121*da4d64d0SSivaprasad Tummala max_dies = power_amd_uncore_get_num_dies(pkg); 122*da4d64d0SSivaprasad Tummala if (max_dies == 0) 123*da4d64d0SSivaprasad Tummala return -1; 124*da4d64d0SSivaprasad Tummala if (die >= max_dies) { 125*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "Die number %02u can not exceed %u", 126*da4d64d0SSivaprasad Tummala die, max_dies); 127*da4d64d0SSivaprasad Tummala return -1; 128*da4d64d0SSivaprasad Tummala } 129*da4d64d0SSivaprasad Tummala 130*da4d64d0SSivaprasad Tummala return 0; 131*da4d64d0SSivaprasad Tummala } 132*da4d64d0SSivaprasad Tummala 133*da4d64d0SSivaprasad Tummala static void 134*da4d64d0SSivaprasad Tummala power_amd_uncore_esmi_init(void) 135*da4d64d0SSivaprasad Tummala { 136*da4d64d0SSivaprasad Tummala if (esmi_init() == ESMI_SUCCESS) { 137*da4d64d0SSivaprasad Tummala if (esmi_hsmp_proto_ver_get(&hsmp_proto_ver) == 138*da4d64d0SSivaprasad Tummala ESMI_SUCCESS) 139*da4d64d0SSivaprasad Tummala esmi_initialized = 1; 140*da4d64d0SSivaprasad Tummala } 141*da4d64d0SSivaprasad Tummala } 142*da4d64d0SSivaprasad Tummala 143*da4d64d0SSivaprasad Tummala int 144*da4d64d0SSivaprasad Tummala power_amd_uncore_init(unsigned int pkg, unsigned int die) 145*da4d64d0SSivaprasad Tummala { 146*da4d64d0SSivaprasad Tummala struct uncore_power_info *ui; 147*da4d64d0SSivaprasad Tummala int ret; 148*da4d64d0SSivaprasad Tummala 149*da4d64d0SSivaprasad Tummala if (!esmi_initialized) { 150*da4d64d0SSivaprasad Tummala ret = esmi_init(); 151*da4d64d0SSivaprasad Tummala if (ret != ESMI_SUCCESS) { 152*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "ESMI Not initialized, drivers not found"); 153*da4d64d0SSivaprasad Tummala return -1; 154*da4d64d0SSivaprasad Tummala } 155*da4d64d0SSivaprasad Tummala ret = esmi_hsmp_proto_ver_get(&hsmp_proto_ver); 156*da4d64d0SSivaprasad Tummala if (ret != ESMI_SUCCESS) { 157*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "HSMP Proto Version Get failed with " 158*da4d64d0SSivaprasad Tummala "error %s", esmi_get_err_msg(ret)); 159*da4d64d0SSivaprasad Tummala esmi_exit(); 160*da4d64d0SSivaprasad Tummala return -1; 161*da4d64d0SSivaprasad Tummala } 162*da4d64d0SSivaprasad Tummala esmi_initialized = 1; 163*da4d64d0SSivaprasad Tummala } 164*da4d64d0SSivaprasad Tummala 165*da4d64d0SSivaprasad Tummala ret = check_pkg_die_values(pkg, die); 166*da4d64d0SSivaprasad Tummala if (ret < 0) 167*da4d64d0SSivaprasad Tummala return -1; 168*da4d64d0SSivaprasad Tummala 169*da4d64d0SSivaprasad Tummala ui = &uncore_info[pkg][die]; 170*da4d64d0SSivaprasad Tummala ui->die = die; 171*da4d64d0SSivaprasad Tummala ui->pkg = pkg; 172*da4d64d0SSivaprasad Tummala 173*da4d64d0SSivaprasad Tummala /* Init for setting uncore die frequency */ 174*da4d64d0SSivaprasad Tummala if (power_init_for_setting_uncore_freq(ui) < 0) { 175*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "Cannot init for setting uncore frequency for " 176*da4d64d0SSivaprasad Tummala "pkg %02u die %02u", pkg, die); 177*da4d64d0SSivaprasad Tummala return -1; 178*da4d64d0SSivaprasad Tummala } 179*da4d64d0SSivaprasad Tummala 180*da4d64d0SSivaprasad Tummala /* Get the available frequencies */ 181*da4d64d0SSivaprasad Tummala if (power_get_available_uncore_freqs(ui) < 0) { 182*da4d64d0SSivaprasad Tummala POWER_LOG(DEBUG, "Cannot get available uncore frequencies of " 183*da4d64d0SSivaprasad Tummala "pkg %02u die %02u", pkg, die); 184*da4d64d0SSivaprasad Tummala return -1; 185*da4d64d0SSivaprasad Tummala } 186*da4d64d0SSivaprasad Tummala 187*da4d64d0SSivaprasad Tummala return 0; 188*da4d64d0SSivaprasad Tummala } 189*da4d64d0SSivaprasad Tummala 190*da4d64d0SSivaprasad Tummala int 191*da4d64d0SSivaprasad Tummala power_amd_uncore_exit(unsigned int pkg, unsigned int die) 192*da4d64d0SSivaprasad Tummala { 193*da4d64d0SSivaprasad Tummala struct uncore_power_info *ui; 194*da4d64d0SSivaprasad Tummala 195*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 196*da4d64d0SSivaprasad Tummala if (ret < 0) 197*da4d64d0SSivaprasad Tummala return -1; 198*da4d64d0SSivaprasad Tummala 199*da4d64d0SSivaprasad Tummala ui = &uncore_info[pkg][die]; 200*da4d64d0SSivaprasad Tummala ui->nb_freqs = 0; 201*da4d64d0SSivaprasad Tummala 202*da4d64d0SSivaprasad Tummala if (esmi_initialized) { 203*da4d64d0SSivaprasad Tummala esmi_exit(); 204*da4d64d0SSivaprasad Tummala esmi_initialized = 0; 205*da4d64d0SSivaprasad Tummala } 206*da4d64d0SSivaprasad Tummala 207*da4d64d0SSivaprasad Tummala return 0; 208*da4d64d0SSivaprasad Tummala } 209*da4d64d0SSivaprasad Tummala 210*da4d64d0SSivaprasad Tummala uint32_t 211*da4d64d0SSivaprasad Tummala power_get_amd_uncore_freq(unsigned int pkg, unsigned int die) 212*da4d64d0SSivaprasad Tummala { 213*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 214*da4d64d0SSivaprasad Tummala if (ret < 0) 215*da4d64d0SSivaprasad Tummala return -1; 216*da4d64d0SSivaprasad Tummala 217*da4d64d0SSivaprasad Tummala return uncore_info[pkg][die].curr_idx; 218*da4d64d0SSivaprasad Tummala } 219*da4d64d0SSivaprasad Tummala 220*da4d64d0SSivaprasad Tummala int 221*da4d64d0SSivaprasad Tummala power_set_amd_uncore_freq(unsigned int pkg, unsigned int die, uint32_t index) 222*da4d64d0SSivaprasad Tummala { 223*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 224*da4d64d0SSivaprasad Tummala if (ret < 0) 225*da4d64d0SSivaprasad Tummala return -1; 226*da4d64d0SSivaprasad Tummala 227*da4d64d0SSivaprasad Tummala return set_uncore_freq_internal(&(uncore_info[pkg][die]), index); 228*da4d64d0SSivaprasad Tummala } 229*da4d64d0SSivaprasad Tummala 230*da4d64d0SSivaprasad Tummala int 231*da4d64d0SSivaprasad Tummala power_amd_uncore_freq_max(unsigned int pkg, unsigned int die) 232*da4d64d0SSivaprasad Tummala { 233*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 234*da4d64d0SSivaprasad Tummala if (ret < 0) 235*da4d64d0SSivaprasad Tummala return -1; 236*da4d64d0SSivaprasad Tummala 237*da4d64d0SSivaprasad Tummala return set_uncore_freq_internal(&(uncore_info[pkg][die]), 0); 238*da4d64d0SSivaprasad Tummala } 239*da4d64d0SSivaprasad Tummala 240*da4d64d0SSivaprasad Tummala 241*da4d64d0SSivaprasad Tummala int 242*da4d64d0SSivaprasad Tummala power_amd_uncore_freq_min(unsigned int pkg, unsigned int die) 243*da4d64d0SSivaprasad Tummala { 244*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 245*da4d64d0SSivaprasad Tummala if (ret < 0) 246*da4d64d0SSivaprasad Tummala return -1; 247*da4d64d0SSivaprasad Tummala 248*da4d64d0SSivaprasad Tummala struct uncore_power_info *ui = &uncore_info[pkg][die]; 249*da4d64d0SSivaprasad Tummala 250*da4d64d0SSivaprasad Tummala return set_uncore_freq_internal(&(uncore_info[pkg][die]), ui->nb_freqs - 1); 251*da4d64d0SSivaprasad Tummala } 252*da4d64d0SSivaprasad Tummala 253*da4d64d0SSivaprasad Tummala int 254*da4d64d0SSivaprasad Tummala power_amd_uncore_freqs(unsigned int pkg, unsigned int die, uint32_t *freqs, uint32_t num) 255*da4d64d0SSivaprasad Tummala { 256*da4d64d0SSivaprasad Tummala struct uncore_power_info *ui; 257*da4d64d0SSivaprasad Tummala 258*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 259*da4d64d0SSivaprasad Tummala if (ret < 0) 260*da4d64d0SSivaprasad Tummala return -1; 261*da4d64d0SSivaprasad Tummala 262*da4d64d0SSivaprasad Tummala if (freqs == NULL) { 263*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "NULL buffer supplied"); 264*da4d64d0SSivaprasad Tummala return 0; 265*da4d64d0SSivaprasad Tummala } 266*da4d64d0SSivaprasad Tummala 267*da4d64d0SSivaprasad Tummala ui = &uncore_info[pkg][die]; 268*da4d64d0SSivaprasad Tummala if (num < ui->nb_freqs) { 269*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "Buffer size is not enough"); 270*da4d64d0SSivaprasad Tummala return 0; 271*da4d64d0SSivaprasad Tummala } 272*da4d64d0SSivaprasad Tummala rte_memcpy(freqs, ui->freqs, ui->nb_freqs * sizeof(uint32_t)); 273*da4d64d0SSivaprasad Tummala 274*da4d64d0SSivaprasad Tummala return ui->nb_freqs; 275*da4d64d0SSivaprasad Tummala } 276*da4d64d0SSivaprasad Tummala 277*da4d64d0SSivaprasad Tummala int 278*da4d64d0SSivaprasad Tummala power_amd_uncore_get_num_freqs(unsigned int pkg, unsigned int die) 279*da4d64d0SSivaprasad Tummala { 280*da4d64d0SSivaprasad Tummala int ret = check_pkg_die_values(pkg, die); 281*da4d64d0SSivaprasad Tummala if (ret < 0) 282*da4d64d0SSivaprasad Tummala return -1; 283*da4d64d0SSivaprasad Tummala 284*da4d64d0SSivaprasad Tummala return uncore_info[pkg][die].nb_freqs; 285*da4d64d0SSivaprasad Tummala } 286*da4d64d0SSivaprasad Tummala 287*da4d64d0SSivaprasad Tummala unsigned int 288*da4d64d0SSivaprasad Tummala power_amd_uncore_get_num_pkgs(void) 289*da4d64d0SSivaprasad Tummala { 290*da4d64d0SSivaprasad Tummala uint32_t num_pkgs = 0; 291*da4d64d0SSivaprasad Tummala int ret; 292*da4d64d0SSivaprasad Tummala 293*da4d64d0SSivaprasad Tummala if (esmi_initialized) { 294*da4d64d0SSivaprasad Tummala ret = esmi_number_of_sockets_get(&num_pkgs); 295*da4d64d0SSivaprasad Tummala if (ret != ESMI_SUCCESS) { 296*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "Failed to get number of sockets"); 297*da4d64d0SSivaprasad Tummala num_pkgs = 0; 298*da4d64d0SSivaprasad Tummala } 299*da4d64d0SSivaprasad Tummala } 300*da4d64d0SSivaprasad Tummala return num_pkgs; 301*da4d64d0SSivaprasad Tummala } 302*da4d64d0SSivaprasad Tummala 303*da4d64d0SSivaprasad Tummala unsigned int 304*da4d64d0SSivaprasad Tummala power_amd_uncore_get_num_dies(unsigned int pkg) 305*da4d64d0SSivaprasad Tummala { 306*da4d64d0SSivaprasad Tummala if (pkg >= power_amd_uncore_get_num_pkgs()) { 307*da4d64d0SSivaprasad Tummala POWER_LOG(ERR, "Invalid package ID"); 308*da4d64d0SSivaprasad Tummala return 0; 309*da4d64d0SSivaprasad Tummala } 310*da4d64d0SSivaprasad Tummala 311*da4d64d0SSivaprasad Tummala return 1; 312*da4d64d0SSivaprasad Tummala } 313*da4d64d0SSivaprasad Tummala 314*da4d64d0SSivaprasad Tummala static struct rte_power_uncore_ops amd_uncore_ops = { 315*da4d64d0SSivaprasad Tummala .name = "amd-hsmp", 316*da4d64d0SSivaprasad Tummala .cb = power_amd_uncore_esmi_init, 317*da4d64d0SSivaprasad Tummala .init = power_amd_uncore_init, 318*da4d64d0SSivaprasad Tummala .exit = power_amd_uncore_exit, 319*da4d64d0SSivaprasad Tummala .get_avail_freqs = power_amd_uncore_freqs, 320*da4d64d0SSivaprasad Tummala .get_num_pkgs = power_amd_uncore_get_num_pkgs, 321*da4d64d0SSivaprasad Tummala .get_num_dies = power_amd_uncore_get_num_dies, 322*da4d64d0SSivaprasad Tummala .get_num_freqs = power_amd_uncore_get_num_freqs, 323*da4d64d0SSivaprasad Tummala .get_freq = power_get_amd_uncore_freq, 324*da4d64d0SSivaprasad Tummala .set_freq = power_set_amd_uncore_freq, 325*da4d64d0SSivaprasad Tummala .freq_max = power_amd_uncore_freq_max, 326*da4d64d0SSivaprasad Tummala .freq_min = power_amd_uncore_freq_min, 327*da4d64d0SSivaprasad Tummala }; 328*da4d64d0SSivaprasad Tummala 329*da4d64d0SSivaprasad Tummala RTE_POWER_REGISTER_UNCORE_OPS(amd_uncore_ops); 330