1 // SPDX-License-Identifier: GPL-2.0 2 /* 3 * Intel Speed Select -- Enumerate and control features 4 * Copyright (c) 2019 Intel Corporation. 5 */ 6 7 #include "isst.h" 8 9 static struct isst_platform_ops *isst_ops; 10 11 #define CHECK_CB(_name) \ 12 do { \ 13 if (!isst_ops || !isst_ops->_name) { \ 14 fprintf(stderr, "Invalid ops\n"); \ 15 exit(0); \ 16 } \ 17 } while (0) 18 19 int isst_set_platform_ops(int api_version) 20 { 21 switch (api_version) { 22 case 1: 23 isst_ops = mbox_get_platform_ops(); 24 break; 25 case 2: 26 isst_ops = tpmi_get_platform_ops(); 27 break; 28 default: 29 isst_ops = NULL; 30 break; 31 } 32 33 if (!isst_ops) 34 return -1; 35 return 0; 36 } 37 38 void isst_update_platform_param(enum isst_platform_param param, int value) 39 { 40 CHECK_CB(update_platform_param); 41 42 isst_ops->update_platform_param(param, value); 43 } 44 45 int isst_get_disp_freq_multiplier(void) 46 { 47 CHECK_CB(get_disp_freq_multiplier); 48 return isst_ops->get_disp_freq_multiplier(); 49 } 50 51 int isst_get_trl_max_levels(void) 52 { 53 CHECK_CB(get_trl_max_levels); 54 return isst_ops->get_trl_max_levels(); 55 } 56 57 char *isst_get_trl_level_name(int level) 58 { 59 CHECK_CB(get_trl_level_name); 60 return isst_ops->get_trl_level_name(level); 61 } 62 63 int isst_is_punit_valid(struct isst_id *id) 64 { 65 CHECK_CB(is_punit_valid); 66 return isst_ops->is_punit_valid(id); 67 } 68 69 int isst_send_msr_command(unsigned int cpu, unsigned int msr, int write, 70 unsigned long long *req_resp) 71 { 72 struct isst_if_msr_cmds msr_cmds; 73 const char *pathname = "/dev/isst_interface"; 74 FILE *outf = get_output_file(); 75 int fd; 76 77 fd = open(pathname, O_RDWR); 78 if (fd < 0) 79 err(-1, "%s open failed", pathname); 80 81 msr_cmds.cmd_count = 1; 82 msr_cmds.msr_cmd[0].logical_cpu = cpu; 83 msr_cmds.msr_cmd[0].msr = msr; 84 msr_cmds.msr_cmd[0].read_write = write; 85 if (write) 86 msr_cmds.msr_cmd[0].data = *req_resp; 87 88 if (ioctl(fd, ISST_IF_MSR_COMMAND, &msr_cmds) == -1) { 89 perror("ISST_IF_MSR_COMMAND"); 90 fprintf(outf, "Error: msr_cmd cpu:%d msr:%x read_write:%d\n", 91 cpu, msr, write); 92 } else { 93 if (!write) 94 *req_resp = msr_cmds.msr_cmd[0].data; 95 96 debug_printf( 97 "msr_cmd response: cpu:%d msr:%x rd_write:%x resp:%llx %llx\n", 98 cpu, msr, write, *req_resp, msr_cmds.msr_cmd[0].data); 99 } 100 101 close(fd); 102 103 return 0; 104 } 105 106 int isst_read_pm_config(struct isst_id *id, int *cp_state, int *cp_cap) 107 { 108 CHECK_CB(read_pm_config); 109 return isst_ops->read_pm_config(id, cp_state, cp_cap); 110 } 111 112 int isst_get_ctdp_levels(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev) 113 { 114 CHECK_CB(get_config_levels); 115 return isst_ops->get_config_levels(id, pkg_dev); 116 } 117 118 int isst_get_ctdp_control(struct isst_id *id, int config_index, 119 struct isst_pkg_ctdp_level_info *ctdp_level) 120 { 121 CHECK_CB(get_ctdp_control); 122 return isst_ops->get_ctdp_control(id, config_index, ctdp_level); 123 } 124 125 int isst_get_tdp_info(struct isst_id *id, int config_index, 126 struct isst_pkg_ctdp_level_info *ctdp_level) 127 { 128 CHECK_CB(get_tdp_info); 129 return isst_ops->get_tdp_info(id, config_index, ctdp_level); 130 } 131 132 int isst_get_pwr_info(struct isst_id *id, int config_index, 133 struct isst_pkg_ctdp_level_info *ctdp_level) 134 { 135 CHECK_CB(get_pwr_info); 136 return isst_ops->get_pwr_info(id, config_index, ctdp_level); 137 } 138 139 int isst_get_coremask_info(struct isst_id *id, int config_index, 140 struct isst_pkg_ctdp_level_info *ctdp_level) 141 { 142 CHECK_CB(get_coremask_info); 143 return isst_ops->get_coremask_info(id, config_index, ctdp_level); 144 } 145 146 int isst_get_get_trl_from_msr(struct isst_id *id, int *trl) 147 { 148 unsigned long long msr_trl; 149 int ret; 150 151 ret = isst_send_msr_command(id->cpu, 0x1AD, 0, &msr_trl); 152 if (ret) 153 return ret; 154 155 trl[0] = msr_trl & GENMASK(7, 0); 156 trl[1] = (msr_trl & GENMASK(15, 8)) >> 8; 157 trl[2] = (msr_trl & GENMASK(23, 16)) >> 16; 158 trl[3] = (msr_trl & GENMASK(31, 24)) >> 24; 159 trl[4] = (msr_trl & GENMASK(39, 32)) >> 32; 160 trl[5] = (msr_trl & GENMASK(47, 40)) >> 40; 161 trl[6] = (msr_trl & GENMASK(55, 48)) >> 48; 162 trl[7] = (msr_trl & GENMASK(63, 56)) >> 56; 163 164 return 0; 165 } 166 167 int isst_get_get_trl(struct isst_id *id, int level, int avx_level, int *trl) 168 { 169 CHECK_CB(get_get_trl); 170 return isst_ops->get_get_trl(id, level, avx_level, trl); 171 } 172 173 int isst_get_get_trls(struct isst_id *id, int level, struct isst_pkg_ctdp_level_info *ctdp_level) 174 { 175 CHECK_CB(get_get_trls); 176 return isst_ops->get_get_trls(id, level, ctdp_level); 177 } 178 179 int isst_get_trl_bucket_info(struct isst_id *id, int level, unsigned long long *buckets_info) 180 { 181 CHECK_CB(get_trl_bucket_info); 182 return isst_ops->get_trl_bucket_info(id, level, buckets_info); 183 } 184 185 int isst_set_tdp_level(struct isst_id *id, int tdp_level) 186 { 187 CHECK_CB(set_tdp_level); 188 return isst_ops->set_tdp_level(id, tdp_level); 189 } 190 191 int isst_get_pbf_info(struct isst_id *id, int level, struct isst_pbf_info *pbf_info) 192 { 193 struct isst_pkg_ctdp_level_info ctdp_level; 194 struct isst_pkg_ctdp pkg_dev; 195 int ret; 196 197 ret = isst_get_ctdp_levels(id, &pkg_dev); 198 if (ret) { 199 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); 200 return ret; 201 } 202 203 if (level > pkg_dev.levels) { 204 isst_display_error_info_message(1, "Invalid level", 1, level); 205 return -1; 206 } 207 208 ret = isst_get_ctdp_control(id, level, &ctdp_level); 209 if (ret) 210 return ret; 211 212 if (!ctdp_level.pbf_support) { 213 isst_display_error_info_message(1, "base-freq feature is not present at this level", 1, level); 214 return -1; 215 } 216 217 pbf_info->core_cpumask_size = alloc_cpu_set(&pbf_info->core_cpumask); 218 219 CHECK_CB(get_pbf_info); 220 return isst_ops->get_pbf_info(id, level, pbf_info); 221 } 222 223 int isst_set_pbf_fact_status(struct isst_id *id, int pbf, int enable) 224 { 225 CHECK_CB(set_pbf_fact_status); 226 return isst_ops->set_pbf_fact_status(id, pbf, enable); 227 } 228 229 230 231 int isst_get_fact_info(struct isst_id *id, int level, int fact_bucket, struct isst_fact_info *fact_info) 232 { 233 struct isst_pkg_ctdp_level_info ctdp_level; 234 struct isst_pkg_ctdp pkg_dev; 235 int ret; 236 237 ret = isst_get_ctdp_levels(id, &pkg_dev); 238 if (ret) { 239 isst_display_error_info_message(1, "Failed to get number of levels", 0, 0); 240 return ret; 241 } 242 243 if (level > pkg_dev.levels) { 244 isst_display_error_info_message(1, "Invalid level", 1, level); 245 return -1; 246 } 247 248 ret = isst_get_ctdp_control(id, level, &ctdp_level); 249 if (ret) 250 return ret; 251 252 if (!ctdp_level.fact_support) { 253 isst_display_error_info_message(1, "turbo-freq feature is not present at this level", 1, level); 254 return -1; 255 } 256 CHECK_CB(get_fact_info); 257 return isst_ops->get_fact_info(id, level, fact_bucket, fact_info); 258 } 259 260 int isst_get_trl(struct isst_id *id, unsigned long long *trl) 261 { 262 int ret; 263 264 ret = isst_send_msr_command(id->cpu, 0x1AD, 0, trl); 265 if (ret) 266 return ret; 267 268 return 0; 269 } 270 271 int isst_set_trl(struct isst_id *id, unsigned long long trl) 272 { 273 int ret; 274 275 if (!trl) 276 trl = 0xFFFFFFFFFFFFFFFFULL; 277 278 ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &trl); 279 if (ret) 280 return ret; 281 282 return 0; 283 } 284 285 int isst_set_trl_from_current_tdp(struct isst_id *id, unsigned long long trl) 286 { 287 unsigned long long msr_trl; 288 int ret; 289 290 if (id->cpu < 0) 291 return 0; 292 293 if (trl) { 294 msr_trl = trl; 295 } else { 296 struct isst_pkg_ctdp pkg_dev; 297 int trl[8]; 298 int i; 299 300 ret = isst_get_ctdp_levels(id, &pkg_dev); 301 if (ret) 302 return ret; 303 304 ret = isst_get_get_trl(id, pkg_dev.current_level, 0, trl); 305 if (ret) 306 return ret; 307 308 msr_trl = 0; 309 for (i = 0; i < 8; ++i) { 310 unsigned long long _trl = trl[i]; 311 312 msr_trl |= (_trl << (i * 8)); 313 } 314 } 315 ret = isst_send_msr_command(id->cpu, 0x1AD, 1, &msr_trl); 316 if (ret) 317 return ret; 318 319 return 0; 320 } 321 322 /* Return 1 if locked */ 323 int isst_get_config_tdp_lock_status(struct isst_id *id) 324 { 325 unsigned long long tdp_control = 0; 326 int ret; 327 328 ret = isst_send_msr_command(id->cpu, 0x64b, 0, &tdp_control); 329 if (ret) 330 return ret; 331 332 ret = !!(tdp_control & BIT(31)); 333 334 return ret; 335 } 336 337 void isst_get_process_ctdp_complete(struct isst_id *id, struct isst_pkg_ctdp *pkg_dev) 338 { 339 int i; 340 341 if (!pkg_dev->processed) 342 return; 343 344 for (i = 0; i < pkg_dev->levels; ++i) { 345 struct isst_pkg_ctdp_level_info *ctdp_level; 346 347 ctdp_level = &pkg_dev->ctdp_level[i]; 348 if (ctdp_level->pbf_support) 349 free_cpu_set(ctdp_level->pbf_info.core_cpumask); 350 free_cpu_set(ctdp_level->core_cpumask); 351 } 352 } 353 354 void isst_adjust_uncore_freq(struct isst_id *id, int config_index, 355 struct isst_pkg_ctdp_level_info *ctdp_level) 356 { 357 CHECK_CB(adjust_uncore_freq); 358 return isst_ops->adjust_uncore_freq(id, config_index, ctdp_level); 359 } 360 361 int isst_get_process_ctdp(struct isst_id *id, int tdp_level, struct isst_pkg_ctdp *pkg_dev) 362 { 363 int i, ret, valid = 0; 364 365 if (pkg_dev->processed) 366 return 0; 367 368 ret = isst_get_ctdp_levels(id, pkg_dev); 369 if (ret) 370 return ret; 371 372 debug_printf("cpu: %d ctdp enable:%d current level: %d levels:%d\n", 373 id->cpu, pkg_dev->enabled, pkg_dev->current_level, 374 pkg_dev->levels); 375 376 if (tdp_level != 0xff && tdp_level > pkg_dev->levels) { 377 isst_display_error_info_message(1, "Invalid level", 0, 0); 378 return -1; 379 } 380 381 if (!pkg_dev->enabled) 382 isst_display_error_info_message(0, "perf-profile feature is not supported, just base-config level 0 is valid", 0, 0); 383 384 for (i = 0; i <= pkg_dev->levels; ++i) { 385 struct isst_pkg_ctdp_level_info *ctdp_level; 386 387 if (tdp_level != 0xff && i != tdp_level) 388 continue; 389 390 debug_printf("cpu:%d Get Information for TDP level:%d\n", id->cpu, 391 i); 392 ctdp_level = &pkg_dev->ctdp_level[i]; 393 394 ctdp_level->level = i; 395 ctdp_level->control_cpu = id->cpu; 396 ctdp_level->pkg_id = id->pkg; 397 ctdp_level->die_id = id->die; 398 399 ret = isst_get_ctdp_control(id, i, ctdp_level); 400 if (ret) 401 continue; 402 403 valid = 1; 404 pkg_dev->processed = 1; 405 ctdp_level->processed = 1; 406 407 if (ctdp_level->pbf_support) { 408 ret = isst_get_pbf_info(id, i, &ctdp_level->pbf_info); 409 if (!ret) 410 ctdp_level->pbf_found = 1; 411 } 412 413 if (ctdp_level->fact_support) { 414 ret = isst_get_fact_info(id, i, 0xff, 415 &ctdp_level->fact_info); 416 if (ret) 417 return ret; 418 } 419 420 if (!pkg_dev->enabled && is_skx_based_platform()) { 421 int freq; 422 423 freq = get_cpufreq_base_freq(id->cpu); 424 if (freq > 0) { 425 ctdp_level->sse_p1 = freq / 100000; 426 ctdp_level->tdp_ratio = ctdp_level->sse_p1; 427 } 428 429 isst_get_get_trl_from_msr(id, ctdp_level->trl_ratios[0]); 430 isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores); 431 continue; 432 } 433 434 ret = isst_get_tdp_info(id, i, ctdp_level); 435 if (ret) 436 return ret; 437 438 ret = isst_get_pwr_info(id, i, ctdp_level); 439 if (ret) 440 return ret; 441 442 ctdp_level->core_cpumask_size = 443 alloc_cpu_set(&ctdp_level->core_cpumask); 444 ret = isst_get_coremask_info(id, i, ctdp_level); 445 if (ret) 446 return ret; 447 448 ret = isst_get_trl_bucket_info(id, i, &ctdp_level->trl_cores); 449 if (ret) 450 return ret; 451 452 ret = isst_get_get_trls(id, i, ctdp_level); 453 if (ret) 454 return ret; 455 } 456 457 if (!valid) 458 isst_display_error_info_message(0, "Invalid level, Can't get TDP control information at specified levels on cpu", 1, id->cpu); 459 460 return 0; 461 } 462 463 int isst_clos_get_clos_information(struct isst_id *id, int *enable, int *type) 464 { 465 CHECK_CB(get_clos_information); 466 return isst_ops->get_clos_information(id, enable, type); 467 } 468 469 int isst_pm_qos_config(struct isst_id *id, int enable_clos, int priority_type) 470 { 471 CHECK_CB(pm_qos_config); 472 return isst_ops->pm_qos_config(id, enable_clos, priority_type); 473 } 474 475 int isst_pm_get_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config) 476 { 477 CHECK_CB(pm_get_clos); 478 return isst_ops->pm_get_clos(id, clos, clos_config); 479 } 480 481 int isst_set_clos(struct isst_id *id, int clos, struct isst_clos_config *clos_config) 482 { 483 CHECK_CB(set_clos); 484 return isst_ops->set_clos(id, clos, clos_config); 485 } 486 487 int isst_clos_get_assoc_status(struct isst_id *id, int *clos_id) 488 { 489 CHECK_CB(clos_get_assoc_status); 490 return isst_ops->clos_get_assoc_status(id, clos_id); 491 } 492 493 int isst_clos_associate(struct isst_id *id, int clos_id) 494 { 495 CHECK_CB(clos_associate); 496 return isst_ops->clos_associate(id, clos_id); 497 498 } 499