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