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 static int amd_pstate_ut_check_floor_freq(u32 index); 63 64 static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = { 65 {"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid }, 66 {"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled }, 67 {"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf }, 68 {"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }, 69 {"amd_pstate_ut_epp", amd_pstate_ut_epp }, 70 {"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }, 71 {"amd_pstate_ut_check_freq_attrs", amd_pstate_ut_check_freq_attrs }, 72 {"amd_pstate_ut_check_floor_freq", amd_pstate_ut_check_floor_freq }, 73 }; 74 75 static bool test_in_list(const char *list, const char *name) 76 { 77 size_t name_len = strlen(name); 78 const char *p = list; 79 80 while (*p) { 81 const char *sep = strchr(p, ','); 82 size_t token_len = sep ? sep - p : strlen(p); 83 84 if (token_len == name_len && !strncmp(p, name, token_len)) 85 return true; 86 if (!sep) 87 break; 88 p = sep + 1; 89 } 90 91 return false; 92 } 93 94 static bool get_shared_mem(void) 95 { 96 bool result = false; 97 98 if (!boot_cpu_has(X86_FEATURE_CPPC)) 99 result = true; 100 101 return result; 102 } 103 104 /* 105 * check the _CPC object is present in SBIOS. 106 */ 107 static int amd_pstate_ut_acpi_cpc_valid(u32 index) 108 { 109 if (!acpi_cpc_valid()) { 110 pr_err("%s the _CPC object is not present in SBIOS!\n", __func__); 111 return -EINVAL; 112 } 113 114 return 0; 115 } 116 117 /* 118 * check if amd pstate is enabled 119 */ 120 static int amd_pstate_ut_check_enabled(u32 index) 121 { 122 u64 cppc_enable = 0; 123 int ret; 124 125 if (get_shared_mem()) 126 return 0; 127 128 ret = rdmsrq_safe(MSR_AMD_CPPC_ENABLE, &cppc_enable); 129 if (ret) { 130 pr_err("%s rdmsrq_safe MSR_AMD_CPPC_ENABLE ret=%d error!\n", __func__, ret); 131 return ret; 132 } 133 134 if (!cppc_enable) { 135 pr_err("%s amd pstate must be enabled!\n", __func__); 136 return -EINVAL; 137 } 138 139 return 0; 140 } 141 142 /* 143 * check if performance values are reasonable. 144 * highest_perf >= nominal_perf > lowest_nonlinear_perf > lowest_perf > 0 145 */ 146 static int amd_pstate_ut_check_perf(u32 index) 147 { 148 int cpu = 0, ret = 0; 149 u32 highest_perf = 0, nominal_perf = 0, lowest_nonlinear_perf = 0, lowest_perf = 0; 150 u64 cap1 = 0; 151 struct cppc_perf_caps cppc_perf; 152 union perf_cached cur_perf; 153 154 for_each_online_cpu(cpu) { 155 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 156 struct amd_cpudata *cpudata; 157 158 policy = cpufreq_cpu_get(cpu); 159 if (!policy) 160 continue; 161 cpudata = policy->driver_data; 162 163 if (get_shared_mem()) { 164 ret = cppc_get_perf_caps(cpu, &cppc_perf); 165 if (ret) { 166 pr_err("%s cppc_get_perf_caps ret=%d error!\n", __func__, ret); 167 return ret; 168 } 169 170 highest_perf = cppc_perf.highest_perf; 171 nominal_perf = cppc_perf.nominal_perf; 172 lowest_nonlinear_perf = cppc_perf.lowest_nonlinear_perf; 173 lowest_perf = cppc_perf.lowest_perf; 174 } else { 175 ret = rdmsrq_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); 176 if (ret) { 177 pr_err("%s read CPPC_CAP1 ret=%d error!\n", __func__, ret); 178 return ret; 179 } 180 181 highest_perf = FIELD_GET(AMD_CPPC_HIGHEST_PERF_MASK, cap1); 182 nominal_perf = FIELD_GET(AMD_CPPC_NOMINAL_PERF_MASK, cap1); 183 lowest_nonlinear_perf = FIELD_GET(AMD_CPPC_LOWNONLIN_PERF_MASK, cap1); 184 lowest_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1); 185 } 186 187 cur_perf = READ_ONCE(cpudata->perf); 188 if (highest_perf != cur_perf.highest_perf && !cpudata->hw_prefcore) { 189 pr_err("%s cpu%d highest=%d %d highest perf doesn't match\n", 190 __func__, cpu, highest_perf, cur_perf.highest_perf); 191 return -EINVAL; 192 } 193 if (nominal_perf != cur_perf.nominal_perf || 194 (lowest_nonlinear_perf != cur_perf.lowest_nonlinear_perf) || 195 (lowest_perf != cur_perf.lowest_perf)) { 196 pr_err("%s cpu%d nominal=%d %d lowest_nonlinear=%d %d lowest=%d %d, they should be equal!\n", 197 __func__, cpu, nominal_perf, cur_perf.nominal_perf, 198 lowest_nonlinear_perf, cur_perf.lowest_nonlinear_perf, 199 lowest_perf, cur_perf.lowest_perf); 200 return -EINVAL; 201 } 202 203 if (!((highest_perf >= nominal_perf) && 204 (nominal_perf > lowest_nonlinear_perf) && 205 (lowest_nonlinear_perf >= lowest_perf) && 206 (lowest_perf > 0))) { 207 pr_err("%s cpu%d highest=%d >= nominal=%d > lowest_nonlinear=%d > lowest=%d > 0, the formula is incorrect!\n", 208 __func__, cpu, highest_perf, nominal_perf, 209 lowest_nonlinear_perf, lowest_perf); 210 return -EINVAL; 211 } 212 } 213 214 return 0; 215 } 216 217 /* 218 * Check if frequency values are reasonable. 219 * nominal_freq > lowest_nonlinear_freq >= min_freq > 0 220 * max_freq >= lowest_nonlinear_freq 221 * 222 * On most parts the boost frequency is the highest, i.e. 223 * max_freq >= nominal_freq. On heterogeneous designs (e.g. Zen6) a 224 * low-power core can have a maximum frequency below the shared nominal 225 * reference frequency, so only require the boost frequency to sit above 226 * the lowest nonlinear frequency here. 227 * check max freq when set support boost mode. 228 */ 229 static int amd_pstate_ut_check_freq(u32 index) 230 { 231 int cpu = 0; 232 233 for_each_online_cpu(cpu) { 234 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 235 struct amd_cpudata *cpudata; 236 union perf_cached perf; 237 238 policy = cpufreq_cpu_get(cpu); 239 if (!policy) 240 continue; 241 242 cpudata = policy->driver_data; 243 perf = READ_ONCE(cpudata->perf); 244 245 if (!((policy->cpuinfo.max_freq >= cpudata->lowest_nonlinear_freq) && 246 (cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) && 247 (cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) && 248 (policy->cpuinfo.min_freq > 0))) { 249 pr_err("%s cpu%d max=%d, nominal=%d, lowest_nonlinear=%d, min=%d, the formula is incorrect!\n", 250 __func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq, 251 cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq); 252 return -EINVAL; 253 } 254 255 if (perf.bios_min_perf) { 256 u32 bios_min_freq = perf_to_freq(perf, cpudata->nominal_freq, 257 perf.bios_min_perf); 258 259 /* 260 * User set bios_min_freq cannot be trusted to 261 * be within the driver limits. Clamp it similar 262 * to cpufreq_verify_within_cpu_limits(). 263 */ 264 bios_min_freq = clamp_t(u32, bios_min_freq, 265 policy->cpuinfo.min_freq, 266 policy->cpuinfo.max_freq); 267 268 if (bios_min_freq != policy->min) { 269 pr_err("%s cpu%d bios_min_freq=%d policy_min=%d, they should be equal!\n", 270 __func__, cpu, bios_min_freq, policy->min); 271 return -EINVAL; 272 } 273 } else if (cpudata->lowest_nonlinear_freq != policy->min) { 274 pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n", 275 __func__, cpu, cpudata->lowest_nonlinear_freq, policy->min); 276 return -EINVAL; 277 } 278 279 if (cpudata->boost_supported) { 280 if ((policy->max != policy->cpuinfo.max_freq) && 281 (policy->max != cpudata->nominal_freq)) { 282 pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n", 283 __func__, cpu, policy->max, policy->cpuinfo.max_freq, 284 cpudata->nominal_freq); 285 return -EINVAL; 286 } 287 } else { 288 pr_err("%s cpu%d must support boost!\n", __func__, cpu); 289 return -EINVAL; 290 } 291 } 292 293 return 0; 294 } 295 296 static int amd_pstate_set_mode(enum amd_pstate_mode mode) 297 { 298 const char *mode_str = amd_pstate_get_mode_string(mode); 299 300 pr_debug("->setting mode to %s\n", mode_str); 301 302 return amd_pstate_update_status(mode_str, strlen(mode_str)); 303 } 304 305 static int amd_pstate_ut_epp(u32 index) 306 { 307 enum energy_perf_value_index epp_modes[] = { 308 EPP_INDEX_DYNAMIC, 309 EPP_INDEX_POWERSAVE, 310 EPP_INDEX_BALANCE_POWERSAVE, 311 EPP_INDEX_BALANCE_PERFORMANCE, 312 EPP_INDEX_PERFORMANCE, 313 }; 314 char *buf __free(cleanup_page) = NULL; 315 struct cpufreq_policy *policy = NULL; 316 unsigned long orig_dynamic_epp = 0; 317 enum amd_pstate_mode orig_mode; 318 struct amd_cpudata *cpudata; 319 unsigned long orig_policy; 320 int ret, cpu = 0; 321 u16 epp; 322 int i; 323 324 policy = cpufreq_cpu_get(cpu); 325 if (!policy) 326 return -ENODEV; 327 328 orig_mode = amd_pstate_get_status(); 329 if (policy->driver_data) { 330 cpudata = policy->driver_data; 331 orig_dynamic_epp = cpudata->dynamic_epp; 332 } 333 334 /* Drop reference before potential driver change. */ 335 cpufreq_cpu_put(policy); 336 policy = NULL; 337 338 buf = (char *)__get_free_page(GFP_KERNEL); 339 if (!buf) 340 return -ENOMEM; 341 342 ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE); 343 if (ret) 344 goto out; 345 346 policy = cpufreq_cpu_get(cpu); 347 if (!policy) { 348 ret = -ENODEV; 349 goto out; 350 } 351 352 down_write(&policy->rwsem); 353 cpudata = policy->driver_data; 354 orig_policy = cpudata->policy; 355 cpudata->policy = CPUFREQ_POLICY_POWERSAVE; 356 357 for (epp = 0; epp <= U8_MAX; epp++) { 358 u8 val; 359 360 /* write all EPP values */ 361 memset(buf, 0, PAGE_SIZE); 362 snprintf(buf, PAGE_SIZE, "%d", epp); 363 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 364 if (ret < 0) 365 goto out; 366 367 /* check if the EPP value reads back correctly for raw numbers */ 368 memset(buf, 0, PAGE_SIZE); 369 ret = show_energy_performance_preference(policy, buf); 370 if (ret < 0) 371 goto out; 372 strreplace(buf, '\n', '\0'); 373 ret = kstrtou8(buf, 0, &val); 374 if (!ret && epp != val) { 375 pr_err("Raw EPP value mismatch: %d != %d\n", epp, val); 376 ret = -EINVAL; 377 goto out; 378 } 379 } 380 381 for (i = 0; i < ARRAY_SIZE(epp_modes); i++) { 382 memset(buf, 0, PAGE_SIZE); 383 snprintf(buf, PAGE_SIZE, "%s", energy_perf_strings[epp_modes[i]]); 384 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 385 if (ret < 0) 386 goto out; 387 388 memset(buf, 0, PAGE_SIZE); 389 ret = show_energy_performance_preference(policy, buf); 390 if (ret < 0) 391 goto out; 392 strreplace(buf, '\n', '\0'); 393 /* 394 * "dynamic" mode reports the EPP as "dynamic(profile:X)" 395 * Trim at "(" and just compare tie the epp string. 396 */ 397 strreplace(buf, '(', '\0'); 398 399 if (strcmp(buf, energy_perf_strings[epp_modes[i]])) { 400 u8 epp = FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached); 401 402 /* 403 * The preference read back may legitimately differ from the one 404 * written: some platforms (e.g. Zen6) program the same raw EPP 405 * value for more than one named preference, so show() reports the 406 * first name that matches that value. 407 * 408 * If strings mismatch, confirm the CPU is programmed with the correct 409 * EPP value for the mode. This verifies hardware programming while 410 * tolerating such aliasing in driver. 411 */ 412 if (epp == amd_pstate_cpu_epp_values(cpudata->cpu_type)[epp_modes[i]]) 413 continue; 414 415 pr_err("String EPP value mismatch: %s != %s\n", 416 buf, energy_perf_strings[epp_modes[i]]); 417 ret = -EINVAL; 418 goto out; 419 } 420 } 421 422 ret = 0; 423 424 out: 425 if (policy) { 426 cpudata->policy = orig_policy; 427 /* 428 * If the driver had enabled dynamic_epp to begin with, 429 * restore it here before dropping policy reference. 430 */ 431 if (orig_dynamic_epp) { 432 const char * const dynamic_string = energy_perf_strings[epp_modes[0]]; 433 int ret2; 434 435 ret2 = store_energy_performance_preference(policy, 436 dynamic_string, 437 strlen(dynamic_string)); 438 if (!ret && (ret2 < 0)) 439 ret = ret2; 440 } 441 up_write(&policy->rwsem); 442 cpufreq_cpu_put(policy); 443 } 444 445 if (orig_mode != amd_pstate_get_status()) { 446 int ret2; 447 448 ret2 = amd_pstate_set_mode(orig_mode); 449 if (!ret && ret2) 450 ret = ret2; 451 } 452 453 return ret; 454 } 455 456 static int amd_pstate_ut_check_driver(u32 index) 457 { 458 enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE; 459 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 460 int ret; 461 462 for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) { 463 ret = amd_pstate_set_mode(mode1); 464 if (ret) 465 return ret; 466 for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) { 467 if (mode1 == mode2) 468 continue; 469 ret = amd_pstate_set_mode(mode2); 470 if (ret) 471 goto out; 472 } 473 } 474 475 out: 476 if (ret) 477 pr_warn("%s: failed to update status for %s->%s: %d\n", __func__, 478 amd_pstate_get_mode_string(mode1), 479 amd_pstate_get_mode_string(mode2), ret); 480 481 amd_pstate_set_mode(orig_mode); 482 return ret; 483 } 484 485 enum attr_category { 486 ATTR_ALWAYS, 487 ATTR_PREFCORE, 488 ATTR_EPP, 489 ATTR_FLOOR_FREQ, 490 }; 491 492 static const struct { 493 const char *name; 494 enum attr_category category; 495 } expected_freq_attrs[] = { 496 {"amd_pstate_max_freq", ATTR_ALWAYS}, 497 {"amd_pstate_lowest_nonlinear_freq", ATTR_ALWAYS}, 498 {"amd_pstate_highest_perf", ATTR_ALWAYS}, 499 {"amd_pstate_prefcore_ranking", ATTR_PREFCORE}, 500 {"amd_pstate_hw_prefcore", ATTR_PREFCORE}, 501 {"energy_performance_preference", ATTR_EPP}, 502 {"energy_performance_available_preferences", ATTR_EPP}, 503 {"amd_pstate_floor_freq", ATTR_FLOOR_FREQ}, 504 {"amd_pstate_floor_count", ATTR_FLOOR_FREQ}, 505 }; 506 507 static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name) 508 { 509 int j; 510 511 for (j = 0; driver_attrs[j]; j++) { 512 if (!strcmp(driver_attrs[j]->attr.name, name)) 513 return true; 514 } 515 return false; 516 } 517 518 /* 519 * Verify that for each mode the driver's live ->attr array contains exactly 520 * the attributes that should be visible. Expected visibility is derived 521 * independently from hw_prefcore, cpu features, and the current mode — 522 * not from the driver's own visibility functions. 523 */ 524 static int amd_pstate_ut_check_freq_attrs(u32 index) 525 { 526 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 527 static const enum amd_pstate_mode modes[] = { 528 AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED, 529 }; 530 bool has_prefcore, has_floor_freq; 531 int m, i, ret; 532 533 has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO); 534 535 /* 536 * Determine prefcore support from any online CPU's cpudata. 537 * hw_prefcore reflects the platform-wide decision made at init. 538 */ 539 has_prefcore = false; 540 for_each_online_cpu(i) { 541 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 542 struct amd_cpudata *cpudata; 543 544 policy = cpufreq_cpu_get(i); 545 if (!policy) 546 continue; 547 cpudata = policy->driver_data; 548 has_prefcore = cpudata->hw_prefcore; 549 break; 550 } 551 552 for (m = 0; m < ARRAY_SIZE(modes); m++) { 553 struct freq_attr **driver_attrs; 554 555 ret = amd_pstate_set_mode(modes[m]); 556 if (ret) 557 goto out; 558 559 driver_attrs = amd_pstate_get_current_attrs(); 560 if (!driver_attrs) { 561 pr_err("%s: no driver attrs in mode %s\n", 562 __func__, amd_pstate_get_mode_string(modes[m])); 563 ret = -EINVAL; 564 goto out; 565 } 566 567 for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) { 568 bool expected, found; 569 570 switch (expected_freq_attrs[i].category) { 571 case ATTR_ALWAYS: 572 expected = true; 573 break; 574 case ATTR_PREFCORE: 575 expected = has_prefcore; 576 break; 577 case ATTR_EPP: 578 expected = (modes[m] == AMD_PSTATE_ACTIVE); 579 break; 580 case ATTR_FLOOR_FREQ: 581 expected = has_floor_freq; 582 break; 583 default: 584 expected = false; 585 break; 586 } 587 588 found = attr_in_driver(driver_attrs, 589 expected_freq_attrs[i].name); 590 591 if (expected != found) { 592 pr_err("%s: mode %s: attr %s expected %s but is %s\n", 593 __func__, 594 amd_pstate_get_mode_string(modes[m]), 595 expected_freq_attrs[i].name, 596 expected ? "visible" : "hidden", 597 found ? "visible" : "hidden"); 598 ret = -EINVAL; 599 goto out; 600 } 601 } 602 } 603 604 ret = 0; 605 out: 606 amd_pstate_set_mode(orig_mode); 607 return ret; 608 } 609 610 static int amd_pstate_ut_check_floor_freq(u32 index) 611 { 612 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 613 char *buf __free(cleanup_page) = NULL; 614 unsigned int orig_floor_freq; 615 unsigned int floor_freq; 616 int ret, cpu = 0; 617 618 if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO)) 619 return -EOPNOTSUPP; 620 621 policy = cpufreq_cpu_get(cpu); 622 if (!policy) 623 return -ENODEV; 624 625 buf = (char *)__get_free_page(GFP_KERNEL); 626 if (!buf) 627 return -ENOMEM; 628 629 guard(rwsem_write)(&policy->rwsem); 630 631 if (!policy->driver_data) 632 return -ENODEV; 633 634 /* Retrieve original floor frequency */ 635 memset(buf, 0, PAGE_SIZE); 636 ret = show_amd_pstate_floor_freq(policy, buf); 637 if (ret < 0) 638 return ret; 639 640 ret = kstrtou32(buf, 0, &orig_floor_freq); 641 if (ret) 642 return ret; 643 644 memset(buf, 0, PAGE_SIZE); 645 snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq); 646 647 /* Set floor frequency to cpuinfo.min_freq */ 648 ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); 649 if (ret < 0) { 650 pr_err("Failed to set floor frequency to %s\n", buf); 651 return ret; 652 } 653 654 memset(buf, 0, PAGE_SIZE); 655 ret = show_amd_pstate_floor_freq(policy, buf); 656 if (ret < 0) 657 return ret; 658 659 strreplace(buf, '\n', '\0'); 660 ret = kstrtou32(buf, 0, &floor_freq); 661 if (ret) 662 return ret; 663 664 /* Confirm sysfs reflects the change correctly. */ 665 if (floor_freq != policy->cpuinfo.min_freq) { 666 pr_err("Floor frequency value mismatch: %u != %u\n", 667 floor_freq, policy->cpuinfo.min_freq); 668 return -EINVAL; 669 } 670 671 memset(buf, 0, PAGE_SIZE); 672 snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq); 673 674 /* Restore the original value. */ 675 ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); 676 if (ret < 0) { 677 pr_err("Failed to restore floor frequency to %s\n", buf); 678 return ret; 679 } 680 681 return 0; 682 } 683 684 static int __init amd_pstate_ut_init(void) 685 { 686 u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases); 687 enum amd_pstate_mode mode = amd_pstate_get_status(); 688 689 /* don't test if no running amd-pstate driver */ 690 if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE) 691 return -EOPNOTSUPP; 692 693 for (i = 0; i < arr_size; i++) { 694 int ret; 695 696 if (test_list && *test_list && 697 !test_in_list(test_list, amd_pstate_ut_cases[i].name)) 698 continue; 699 700 ret = amd_pstate_ut_cases[i].func(i); 701 702 if (ret) { 703 /* Platform does not support the feature being tested. */ 704 if (ret == -EOPNOTSUPP) { 705 pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name); 706 continue; 707 } 708 pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret); 709 } else { 710 pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name); 711 } 712 } 713 714 return 0; 715 } 716 717 static void __exit amd_pstate_ut_exit(void) 718 { 719 } 720 721 module_init(amd_pstate_ut_init); 722 module_exit(amd_pstate_ut_exit); 723 724 MODULE_AUTHOR("Meng Li <li.meng@amd.com>"); 725 MODULE_DESCRIPTION("AMD P-state driver Test module"); 726 MODULE_LICENSE("GPL"); 727