1 // SPDX-License-Identifier: GPL-2.0-or-later 2 /* 3 * AMD Processor P-state Frequency Driver Unit Test 4 * 5 * Copyright (C) 2022 Advanced Micro Devices, Inc. All Rights Reserved. 6 * 7 * Author: Meng Li <li.meng@amd.com> 8 * 9 * The AMD P-State Unit Test is a test module for testing the amd-pstate 10 * driver. 1) It can help all users to verify their processor support 11 * (SBIOS/Firmware or Hardware). 2) Kernel can have a basic function 12 * test to avoid the kernel regression during the update. 3) We can 13 * introduce more functional or performance tests to align the result 14 * together, it will benefit power and performance scale optimization. 15 * 16 * This driver implements basic framework with plans to enhance it with 17 * additional test cases to improve the depth and coverage of the test. 18 * 19 * See Documentation/admin-guide/pm/amd-pstate.rst Unit Tests for 20 * amd-pstate to get more detail. 21 */ 22 23 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt 24 25 #include <linux/bitfield.h> 26 #include <linux/cpufeature.h> 27 #include <linux/cpufreq.h> 28 #include <linux/kernel.h> 29 #include <linux/module.h> 30 #include <linux/moduleparam.h> 31 #include <linux/mm.h> 32 #include <linux/fs.h> 33 #include <linux/cleanup.h> 34 35 #include <acpi/cppc_acpi.h> 36 37 #include <asm/msr.h> 38 39 #include "amd-pstate.h" 40 41 static char *test_list; 42 module_param(test_list, charp, 0444); 43 MODULE_PARM_DESC(test_list, 44 "Comma-delimited list of tests to run (empty means run all tests)"); 45 DEFINE_FREE(cleanup_page, void *, if (_T) free_page((unsigned long)_T)) 46 47 struct amd_pstate_ut_struct { 48 const char *name; 49 int (*func)(u32 index); 50 }; 51 52 /* 53 * Kernel module for testing the AMD P-State unit test 54 */ 55 static int amd_pstate_ut_acpi_cpc_valid(u32 index); 56 static int amd_pstate_ut_check_enabled(u32 index); 57 static int amd_pstate_ut_check_perf(u32 index); 58 static int amd_pstate_ut_check_freq(u32 index); 59 static int amd_pstate_ut_epp(u32 index); 60 static int amd_pstate_ut_check_driver(u32 index); 61 static int amd_pstate_ut_check_freq_attrs(u32 index); 62 63 static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { 64 {"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid }, 65 {"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled }, 66 {"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf }, 67 {"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }, 68 {"amd_pstate_ut_epp", amd_pstate_ut_epp }, 69 {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }, 70 {"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs }, 71 }; 72 73 static bool test_in_list(const char *list, const char *name) 74 { 75 size_t name_len = strlen(name); 76 const char *p = list; 77 78 while (*p) { 79 const char *sep = strchr(p, ','); 80 size_t token_len = sep ? sep - p : strlen(p); 81 82 if (token_len == name_len && !strncmp(p, name, token_len)) 83 return true; 84 if (!sep) 85 break; 86 p = sep + 1; 87 } 88 89 return false; 90 } 91 92 static bool get_shared_mem(void) 93 { 94 bool result = false; 95 96 if (!boot_cpu_has(X86_FEATURE_CPPC)) 97 result = true; 98 99 return result; 100 } 101 102 /* 103 * check the _CPC object is present in SBIOS. 104 */ 105 static int amd_pstate_ut_acpi_cpc_valid(u32 index) 106 { 107 if (!acpi_cpc_valid()) { 108 pr_err("%s the _CPC object is not present in SBIOS!\n", __func__); 109 return -EINVAL; 110 } 111 112 return 0; 113 } 114 115 /* 116 * check if amd pstate is enabled 117 */ 118 static int amd_pstate_ut_check_enabled(u32 index) 119 { 120 u64 cppc_enable = 0; 121 int ret; 122 123 if (get_shared_mem()) 124 return 0; 125 126 ret = rdmsrq_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable); 127 if (ret) { 128 pr_err("%s rdmsrq_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret); 129 return ret; 130 } 131 132 if (!cppc_enable) { 133 pr_err("%s amd pstate must be enabled!\n", __func__); 134 return -EINVAL; 135 } 136 137 return 0; 138 } 139 140 /* 141 * check if performance values are reasonable. 142 * highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0 143 */ 144 static int amd_pstate_ut_check_perf(u32 index) 145 { 146 int cpu = 0, ret = 0; 147 u32 highest_perf = 0, nominal_perf = 0, lowest_nonlinear_perf = 0, lowest_perf = 0; 148 u64 cap1 = 0; 149 struct cppc_perf_caps cppc_perf; 150 union perf_cached cur_perf; 151 152 for_each_online_cpu(cpu) { 153 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 154 struct amd_cpudata *cpudata; 155 156 policy = cpufreq_cpu_get(cpu); 157 if (!policy) 158 continue; 159 cpudata = policy->driver_data; 160 161 if (get_shared_mem()) { 162 ret = cppc_get_perf_caps(cpu, &cppc_perf); 163 if (ret) { 164 pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret); 165 return ret; 166 } 167 168 highest_perf = cppc_perf.highest_perf; 169 nominal_perf = cppc_perf.nominal_perf; 170 lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf; 171 lowest_perf = cppc_perf.lowest_perf; 172 } else { 173 ret = rdmsrq_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); 174 if (ret) { 175 pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret); 176 return ret; 177 } 178 179 highest_perf = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1); 180 nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1); 181 lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1); 182 lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1); 183 } 184 185 cur_perf = READ_ONCE(cpudata->perf); 186 if (highest_perf != cur_perf.highest_perf && !cpudata->hw_prefcore) { 187 pr_err("%s cpu%d highest=%d %d highest perf doesn't match\n", 188 __func__, cpu, highest_perf, cur_perf.highest_perf); 189 return -EINVAL; 190 } 191 if (nominal_perf != cur_perf.nominal_perf || 192 (lowest_nonlinear_perf != cur_perf.lowest_nonlinear_perf) || 193 (lowest_perf != cur_perf.lowest_perf)) { 194 pr_err("%s cpu%d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n", 195 __func__, cpu, nominal_perf, cur_perf.nominal_perf, 196 lowest_nonlinear_perf, cur_perf.lowest_nonlinear_perf, 197 lowest_perf, cur_perf.lowest_perf); 198 return -EINVAL; 199 } 200 201 if (!((highest_perf >= nominal_perf) && 202 (nominal_perf > lowest_nonlinear_perf) && 203 (lowest_nonlinear_perf >= lowest_perf) && 204 (lowest_perf > 0))) { 205 pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n", 206 __func__, cpu, highest_perf, nominal_perf, 207 lowest_nonlinear_perf, lowest_perf); 208 return -EINVAL; 209 } 210 } 211 212 return 0; 213 } 214 215 /* 216 * Check if frequency values are reasonable. 217 * max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0 218 * check max freq when set support boost mode. 219 */ 220 static int amd_pstate_ut_check_freq(u32 index) 221 { 222 int cpu = 0; 223 224 for_each_online_cpu(cpu) { 225 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 226 struct amd_cpudata *cpudata; 227 228 policy = cpufreq_cpu_get(cpu); 229 if (!policy) 230 continue; 231 cpudata = policy->driver_data; 232 233 if (!((policy->cpuinfo.max_freq >= cpudata->nominal_freq) && 234 (cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) && 235 (cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) && 236 (policy->cpuinfo.min_freq > 0))) { 237 pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n", 238 __func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq, 239 cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq); 240 return -EINVAL; 241 } 242 243 if (cpudata->lowest_nonlinear_freq != policy->min) { 244 pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n", 245 __func__, cpu, cpudata->lowest_nonlinear_freq, policy->min); 246 return -EINVAL; 247 } 248 249 if (cpudata->boost_supported) { 250 if ((policy->max != policy->cpuinfo.max_freq) && 251 (policy->max != cpudata->nominal_freq)) { 252 pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n", 253 __func__, cpu, policy->max, policy->cpuinfo.max_freq, 254 cpudata->nominal_freq); 255 return -EINVAL; 256 } 257 } else { 258 pr_err("%s cpu%d must support boost!\n", __func__, cpu); 259 return -EINVAL; 260 } 261 } 262 263 return 0; 264 } 265 266 static int amd_pstate_set_mode(enum amd_pstate_mode mode) 267 { 268 const char *mode_str = amd_pstate_get_mode_string(mode); 269 270 pr_debug("->setting mode to %s\n", mode_str); 271 272 return amd_pstate_update_status(mode_str, strlen(mode_str)); 273 } 274 275 static int amd_pstate_ut_epp(u32 index) 276 { 277 static const char * const epp_strings[] = { 278 "power", 279 "balance_power", 280 "balance_performance", 281 "performance", 282 }; 283 char *buf __free(cleanup_page) = NULL; 284 struct cpufreq_policy *policy = NULL; 285 enum amd_pstate_mode orig_mode; 286 struct amd_cpudata *cpudata; 287 unsigned long orig_policy; 288 bool orig_dynamic_epp; 289 int ret, cpu = 0; 290 u16 epp; 291 int i; 292 293 policy = cpufreq_cpu_get(cpu); 294 if (!policy) 295 return -ENODEV; 296 297 cpudata = policy->driver_data; 298 orig_mode = amd_pstate_get_status(); 299 orig_dynamic_epp = cpudata->dynamic_epp; 300 301 /* Drop reference before potential driver change. */ 302 cpufreq_cpu_put(policy); 303 policy = NULL; 304 305 buf = (char *)__get_free_page(GFP_KERNEL); 306 if (!buf) 307 return -ENOMEM; 308 309 ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE); 310 if (ret) 311 goto out; 312 313 policy = cpufreq_cpu_get(cpu); 314 if (!policy) { 315 ret = -ENODEV; 316 goto out; 317 } 318 319 down_write(&policy->rwsem); 320 cpudata = policy->driver_data; 321 orig_policy = cpudata->policy; 322 cpudata->policy = CPUFREQ_POLICY_POWERSAVE; 323 324 /* 325 * Disable dynamic EPP before running test. If "orig_dynamic_epp" is 326 * true, the driver will do a redundant switch at the end and there 327 * is no need for enabling it again at the end of the test. 328 */ 329 if (cpudata->dynamic_epp) { 330 pr_debug("Dynamic EPP is enabled, disabling it\n"); 331 amd_pstate_clear_dynamic_epp(policy); 332 } 333 334 for (epp = 0; epp <= U8_MAX; epp++) { 335 u8 val; 336 337 /* write all EPP values */ 338 memset(buf, 0, PAGE_SIZE); 339 snprintf(buf, PAGE_SIZE, "%d", epp); 340 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 341 if (ret < 0) 342 goto out; 343 344 /* check if the EPP value reads back correctly for raw numbers */ 345 memset(buf, 0, PAGE_SIZE); 346 ret = show_energy_performance_preference(policy, buf); 347 if (ret < 0) 348 goto out; 349 strreplace(buf, '\n', '\0'); 350 ret = kstrtou8(buf, 0, &val); 351 if (!ret && epp != val) { 352 pr_err("Raw EPP value mismatch: %d != %d\n", epp, val); 353 ret = -EINVAL; 354 goto out; 355 } 356 } 357 358 for (i = 0; i < ARRAY_SIZE(epp_strings); i++) { 359 memset(buf, 0, PAGE_SIZE); 360 snprintf(buf, PAGE_SIZE, "%s", epp_strings[i]); 361 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 362 if (ret < 0) 363 goto out; 364 365 memset(buf, 0, PAGE_SIZE); 366 ret = show_energy_performance_preference(policy, buf); 367 if (ret < 0) 368 goto out; 369 strreplace(buf, '\n', '\0'); 370 371 if (strcmp(buf, epp_strings[i])) { 372 pr_err("String EPP value mismatch: %s != %s\n", buf, epp_strings[i]); 373 ret = -EINVAL; 374 goto out; 375 } 376 } 377 378 ret = 0; 379 380 out: 381 if (policy) { 382 cpudata->policy = orig_policy; 383 up_write(&policy->rwsem); 384 cpufreq_cpu_put(policy); 385 } 386 387 if (orig_dynamic_epp) { 388 int ret2; 389 390 ret2 = amd_pstate_set_mode(AMD_PSTATE_DISABLE); 391 if (!ret && ret2) 392 ret = ret2; 393 } 394 395 if (orig_mode != amd_pstate_get_status()) { 396 int ret2; 397 398 ret2 = amd_pstate_set_mode(orig_mode); 399 if (!ret && ret2) 400 ret = ret2; 401 } 402 403 return ret; 404 } 405 406 static int amd_pstate_ut_check_driver(u32 index) 407 { 408 enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE; 409 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 410 int ret; 411 412 for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) { 413 ret = amd_pstate_set_mode(mode1); 414 if (ret) 415 return ret; 416 for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) { 417 if (mode1 == mode2) 418 continue; 419 ret = amd_pstate_set_mode(mode2); 420 if (ret) 421 goto out; 422 } 423 } 424 425 out: 426 if (ret) 427 pr_warn("%s: failed to update status for %s->%s: %d\n", __func__, 428 amd_pstate_get_mode_string(mode1), 429 amd_pstate_get_mode_string(mode2), ret); 430 431 amd_pstate_set_mode(orig_mode); 432 return ret; 433 } 434 435 enum attr_category { 436 ATTR_ALWAYS, 437 ATTR_PREFCORE, 438 ATTR_EPP, 439 ATTR_FLOOR_FREQ, 440 }; 441 442 static const struct { 443 const char *name; 444 enum attr_category category; 445 } expected_freq_attrs[] = { 446 {"amd_pstate_max_freq", ATTR_ALWAYS}, 447 {"amd_pstate_lowest_nonlinear_freq", ATTR_ALWAYS}, 448 {"amd_pstate_highest_perf", ATTR_ALWAYS}, 449 {"amd_pstate_prefcore_ranking", ATTR_PREFCORE}, 450 {"amd_pstate_hw_prefcore", ATTR_PREFCORE}, 451 {"energy_performance_preference", ATTR_EPP}, 452 {"energy_performance_available_preferences", ATTR_EPP}, 453 {"amd_pstate_floor_freq", ATTR_FLOOR_FREQ}, 454 {"amd_pstate_floor_count", ATTR_FLOOR_FREQ}, 455 }; 456 457 static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name) 458 { 459 int j; 460 461 for (j = 0; driver_attrs[j]; j++) { 462 if (!strcmp(driver_attrs[j]->attr.name, name)) 463 return true; 464 } 465 return false; 466 } 467 468 /* 469 * Verify that for each mode the driver's live ->attr array contains exactly 470 * the attributes that should be visible. Expected visibility is derived 471 * independently from hw_prefcore, cpu features, and the current mode — 472 * not from the driver's own visibility functions. 473 */ 474 static int amd_pstate_ut_check_freq_attrs(u32 index) 475 { 476 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 477 static const enum amd_pstate_mode modes[] = { 478 AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED, 479 }; 480 bool has_prefcore, has_floor_freq; 481 int m, i, ret; 482 483 has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO); 484 485 /* 486 * Determine prefcore support from any online CPU's cpudata. 487 * hw_prefcore reflects the platform-wide decision made at init. 488 */ 489 has_prefcore = false; 490 for_each_online_cpu(i) { 491 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 492 struct amd_cpudata *cpudata; 493 494 policy = cpufreq_cpu_get(i); 495 if (!policy) 496 continue; 497 cpudata = policy->driver_data; 498 has_prefcore = cpudata->hw_prefcore; 499 break; 500 } 501 502 for (m = 0; m < ARRAY_SIZE(modes); m++) { 503 struct freq_attr **driver_attrs; 504 505 ret = amd_pstate_set_mode(modes[m]); 506 if (ret) 507 goto out; 508 509 driver_attrs = amd_pstate_get_current_attrs(); 510 if (!driver_attrs) { 511 pr_err("%s: no driver attrs in mode %s\n", 512 __func__, amd_pstate_get_mode_string(modes[m])); 513 ret = -EINVAL; 514 goto out; 515 } 516 517 for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) { 518 bool expected, found; 519 520 switch (expected_freq_attrs[i].category) { 521 case ATTR_ALWAYS: 522 expected = true; 523 break; 524 case ATTR_PREFCORE: 525 expected = has_prefcore; 526 break; 527 case ATTR_EPP: 528 expected = (modes[m] == AMD_PSTATE_ACTIVE); 529 break; 530 case ATTR_FLOOR_FREQ: 531 expected = has_floor_freq; 532 break; 533 default: 534 expected = false; 535 break; 536 } 537 538 found = attr_in_driver(driver_attrs, 539 expected_freq_attrs[i].name); 540 541 if (expected != found) { 542 pr_err("%s: mode %s: attr %s expected %s but is %s\n", 543 __func__, 544 amd_pstate_get_mode_string(modes[m]), 545 expected_freq_attrs[i].name, 546 expected ? "visible" : "hidden", 547 found ? "visible" : "hidden"); 548 ret = -EINVAL; 549 goto out; 550 } 551 } 552 } 553 554 ret = 0; 555 out: 556 amd_pstate_set_mode(orig_mode); 557 return ret; 558 } 559 560 static int __init amd_pstate_ut_init(void) 561 { 562 u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases); 563 564 for (i = 0; i < arr_size; i++) { 565 int ret; 566 567 if (test_list && *test_list && 568 !test_in_list(test_list, amd_pstate_ut_cases[i].name)) 569 continue; 570 571 ret = amd_pstate_ut_cases[i].func(i); 572 573 if (ret) 574 pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret); 575 else 576 pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name); 577 } 578 579 return 0; 580 } 581 582 static void __exit amd_pstate_ut_exit(void) 583 { 584 } 585 586 module_init(amd_pstate_ut_init); 587 module_exit(amd_pstate_ut_exit); 588 589 MODULE_AUTHOR("Meng Li <li.meng@amd.com>"); 590 MODULE_DESCRIPTION("AMD P-state driver Test module"); 591 MODULE_LICENSE("GPL"); 592