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 * max_freq >= nominal_freq > lowest_nonlinear_freq > min_freq > 0 220 * check max freq when set support boost mode. 221 */ 222 static int amd_pstate_ut_check_freq(u32 index) 223 { 224 int cpu = 0; 225 226 for_each_online_cpu(cpu) { 227 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 228 struct amd_cpudata *cpudata; 229 230 policy = cpufreq_cpu_get(cpu); 231 if (!policy) 232 continue; 233 cpudata = policy->driver_data; 234 235 if (!((policy->cpuinfo.max_freq >= cpudata->nominal_freq) && 236 (cpudata->nominal_freq > cpudata->lowest_nonlinear_freq) && 237 (cpudata->lowest_nonlinear_freq >= policy->cpuinfo.min_freq) && 238 (policy->cpuinfo.min_freq > 0))) { 239 pr_err("%s cpu%d max=%d >= nominal=%d > lowest_nonlinear=%d > min=%d > 0, the formula is incorrect!\n", 240 __func__, cpu, policy->cpuinfo.max_freq, cpudata->nominal_freq, 241 cpudata->lowest_nonlinear_freq, policy->cpuinfo.min_freq); 242 return -EINVAL; 243 } 244 245 if (cpudata->lowest_nonlinear_freq != policy->min) { 246 pr_err("%s cpu%d cpudata_lowest_nonlinear_freq=%d policy_min=%d, they should be equal!\n", 247 __func__, cpu, cpudata->lowest_nonlinear_freq, policy->min); 248 return -EINVAL; 249 } 250 251 if (cpudata->boost_supported) { 252 if ((policy->max != policy->cpuinfo.max_freq) && 253 (policy->max != cpudata->nominal_freq)) { 254 pr_err("%s cpu%d policy_max=%d should be equal cpu_max=%d or cpu_nominal=%d !\n", 255 __func__, cpu, policy->max, policy->cpuinfo.max_freq, 256 cpudata->nominal_freq); 257 return -EINVAL; 258 } 259 } else { 260 pr_err("%s cpu%d must support boost!\n", __func__, cpu); 261 return -EINVAL; 262 } 263 } 264 265 return 0; 266 } 267 268 static int amd_pstate_set_mode(enum amd_pstate_mode mode) 269 { 270 const char *mode_str = amd_pstate_get_mode_string(mode); 271 272 pr_debug("->setting mode to %s\n", mode_str); 273 274 return amd_pstate_update_status(mode_str, strlen(mode_str)); 275 } 276 277 static int amd_pstate_ut_epp(u32 index) 278 { 279 static const char * const epp_strings[] = { 280 "dynamic", 281 "power", 282 "balance_power", 283 "balance_performance", 284 "performance", 285 }; 286 char *buf __free(cleanup_page) = NULL; 287 struct cpufreq_policy *policy = NULL; 288 unsigned long orig_dynamic_epp = 0; 289 enum amd_pstate_mode orig_mode; 290 struct amd_cpudata *cpudata; 291 unsigned long orig_policy; 292 int ret, cpu = 0; 293 u16 epp; 294 int i; 295 296 policy = cpufreq_cpu_get(cpu); 297 if (!policy) 298 return -ENODEV; 299 300 orig_mode = amd_pstate_get_status(); 301 if (policy->driver_data) { 302 cpudata = policy->driver_data; 303 orig_dynamic_epp = cpudata->dynamic_epp; 304 } 305 306 /* Drop reference before potential driver change. */ 307 cpufreq_cpu_put(policy); 308 policy = NULL; 309 310 buf = (char *)__get_free_page(GFP_KERNEL); 311 if (!buf) 312 return -ENOMEM; 313 314 ret = amd_pstate_set_mode(AMD_PSTATE_ACTIVE); 315 if (ret) 316 goto out; 317 318 policy = cpufreq_cpu_get(cpu); 319 if (!policy) { 320 ret = -ENODEV; 321 goto out; 322 } 323 324 down_write(&policy->rwsem); 325 cpudata = policy->driver_data; 326 orig_policy = cpudata->policy; 327 cpudata->policy = CPUFREQ_POLICY_POWERSAVE; 328 329 for (epp = 0; epp <= U8_MAX; epp++) { 330 u8 val; 331 332 /* write all EPP values */ 333 memset(buf, 0, PAGE_SIZE); 334 snprintf(buf, PAGE_SIZE, "%d", epp); 335 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 336 if (ret < 0) 337 goto out; 338 339 /* check if the EPP value reads back correctly for raw numbers */ 340 memset(buf, 0, PAGE_SIZE); 341 ret = show_energy_performance_preference(policy, buf); 342 if (ret < 0) 343 goto out; 344 strreplace(buf, '\n', '\0'); 345 ret = kstrtou8(buf, 0, &val); 346 if (!ret && epp != val) { 347 pr_err("Raw EPP value mismatch: %d != %d\n", epp, val); 348 ret = -EINVAL; 349 goto out; 350 } 351 } 352 353 for (i = 0; i < ARRAY_SIZE(epp_strings); i++) { 354 memset(buf, 0, PAGE_SIZE); 355 snprintf(buf, PAGE_SIZE, "%s", epp_strings[i]); 356 ret = store_energy_performance_preference(policy, buf, strlen(buf)); 357 if (ret < 0) 358 goto out; 359 360 memset(buf, 0, PAGE_SIZE); 361 ret = show_energy_performance_preference(policy, buf); 362 if (ret < 0) 363 goto out; 364 strreplace(buf, '\n', '\0'); 365 /* 366 * "dynamic" mode reports the EPP as "dynamic(profile:X)" 367 * Trim at "(" and just compare tie the epp string. 368 */ 369 strreplace(buf, '(', '\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 /* 384 * If the driver had enabled dynamic_epp to begin with, 385 * restore it here before dropping policy reference. 386 */ 387 if (orig_dynamic_epp) { 388 int ret2; 389 390 ret2 = store_energy_performance_preference(policy, 391 epp_strings[0], 392 strlen(epp_strings[0])); 393 if (!ret && (ret2 < 0)) 394 ret = ret2; 395 } 396 up_write(&policy->rwsem); 397 cpufreq_cpu_put(policy); 398 } 399 400 if (orig_mode != amd_pstate_get_status()) { 401 int ret2; 402 403 ret2 = amd_pstate_set_mode(orig_mode); 404 if (!ret && ret2) 405 ret = ret2; 406 } 407 408 return ret; 409 } 410 411 static int amd_pstate_ut_check_driver(u32 index) 412 { 413 enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE; 414 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 415 int ret; 416 417 for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) { 418 ret = amd_pstate_set_mode(mode1); 419 if (ret) 420 return ret; 421 for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) { 422 if (mode1 == mode2) 423 continue; 424 ret = amd_pstate_set_mode(mode2); 425 if (ret) 426 goto out; 427 } 428 } 429 430 out: 431 if (ret) 432 pr_warn("%s: failed to update status for %s->%s: %d\n", __func__, 433 amd_pstate_get_mode_string(mode1), 434 amd_pstate_get_mode_string(mode2), ret); 435 436 amd_pstate_set_mode(orig_mode); 437 return ret; 438 } 439 440 enum attr_category { 441 ATTR_ALWAYS, 442 ATTR_PREFCORE, 443 ATTR_EPP, 444 ATTR_FLOOR_FREQ, 445 }; 446 447 static const struct { 448 const char *name; 449 enum attr_category category; 450 } expected_freq_attrs[] = { 451 {"amd_pstate_max_freq", ATTR_ALWAYS}, 452 {"amd_pstate_lowest_nonlinear_freq", ATTR_ALWAYS}, 453 {"amd_pstate_highest_perf", ATTR_ALWAYS}, 454 {"amd_pstate_prefcore_ranking", ATTR_PREFCORE}, 455 {"amd_pstate_hw_prefcore", ATTR_PREFCORE}, 456 {"energy_performance_preference", ATTR_EPP}, 457 {"energy_performance_available_preferences", ATTR_EPP}, 458 {"amd_pstate_floor_freq", ATTR_FLOOR_FREQ}, 459 {"amd_pstate_floor_count", ATTR_FLOOR_FREQ}, 460 }; 461 462 static bool attr_in_driver(struct freq_attr **driver_attrs, const char *name) 463 { 464 int j; 465 466 for (j = 0; driver_attrs[j]; j++) { 467 if (!strcmp(driver_attrs[j]->attr.name, name)) 468 return true; 469 } 470 return false; 471 } 472 473 /* 474 * Verify that for each mode the driver's live ->attr array contains exactly 475 * the attributes that should be visible. Expected visibility is derived 476 * independently from hw_prefcore, cpu features, and the current mode — 477 * not from the driver's own visibility functions. 478 */ 479 static int amd_pstate_ut_check_freq_attrs(u32 index) 480 { 481 enum amd_pstate_mode orig_mode = amd_pstate_get_status(); 482 static const enum amd_pstate_mode modes[] = { 483 AMD_PSTATE_PASSIVE, AMD_PSTATE_ACTIVE, AMD_PSTATE_GUIDED, 484 }; 485 bool has_prefcore, has_floor_freq; 486 int m, i, ret; 487 488 has_floor_freq = cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO); 489 490 /* 491 * Determine prefcore support from any online CPU's cpudata. 492 * hw_prefcore reflects the platform-wide decision made at init. 493 */ 494 has_prefcore = false; 495 for_each_online_cpu(i) { 496 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 497 struct amd_cpudata *cpudata; 498 499 policy = cpufreq_cpu_get(i); 500 if (!policy) 501 continue; 502 cpudata = policy->driver_data; 503 has_prefcore = cpudata->hw_prefcore; 504 break; 505 } 506 507 for (m = 0; m < ARRAY_SIZE(modes); m++) { 508 struct freq_attr **driver_attrs; 509 510 ret = amd_pstate_set_mode(modes[m]); 511 if (ret) 512 goto out; 513 514 driver_attrs = amd_pstate_get_current_attrs(); 515 if (!driver_attrs) { 516 pr_err("%s: no driver attrs in mode %s\n", 517 __func__, amd_pstate_get_mode_string(modes[m])); 518 ret = -EINVAL; 519 goto out; 520 } 521 522 for (i = 0; i < ARRAY_SIZE(expected_freq_attrs); i++) { 523 bool expected, found; 524 525 switch (expected_freq_attrs[i].category) { 526 case ATTR_ALWAYS: 527 expected = true; 528 break; 529 case ATTR_PREFCORE: 530 expected = has_prefcore; 531 break; 532 case ATTR_EPP: 533 expected = (modes[m] == AMD_PSTATE_ACTIVE); 534 break; 535 case ATTR_FLOOR_FREQ: 536 expected = has_floor_freq; 537 break; 538 default: 539 expected = false; 540 break; 541 } 542 543 found = attr_in_driver(driver_attrs, 544 expected_freq_attrs[i].name); 545 546 if (expected != found) { 547 pr_err("%s: mode %s: attr %s expected %s but is %s\n", 548 __func__, 549 amd_pstate_get_mode_string(modes[m]), 550 expected_freq_attrs[i].name, 551 expected ? "visible" : "hidden", 552 found ? "visible" : "hidden"); 553 ret = -EINVAL; 554 goto out; 555 } 556 } 557 } 558 559 ret = 0; 560 out: 561 amd_pstate_set_mode(orig_mode); 562 return ret; 563 } 564 565 static int amd_pstate_ut_check_floor_freq(u32 index) 566 { 567 struct cpufreq_policy *policy __free(put_cpufreq_policy) = NULL; 568 char *buf __free(cleanup_page) = NULL; 569 unsigned int orig_floor_freq; 570 unsigned int floor_freq; 571 int ret, cpu = 0; 572 573 if (!cpu_feature_enabled(X86_FEATURE_CPPC_PERF_PRIO)) 574 return -EOPNOTSUPP; 575 576 policy = cpufreq_cpu_get(cpu); 577 if (!policy) 578 return -ENODEV; 579 580 buf = (char *)__get_free_page(GFP_KERNEL); 581 if (!buf) 582 return -ENOMEM; 583 584 guard(rwsem_write)(&policy->rwsem); 585 586 if (!policy->driver_data) 587 return -ENODEV; 588 589 /* Retrieve original floor frequency */ 590 memset(buf, 0, PAGE_SIZE); 591 ret = show_amd_pstate_floor_freq(policy, buf); 592 if (ret < 0) 593 return ret; 594 595 ret = kstrtou32(buf, 0, &orig_floor_freq); 596 if (ret) 597 return ret; 598 599 memset(buf, 0, PAGE_SIZE); 600 snprintf(buf, PAGE_SIZE, "%u", policy->cpuinfo.min_freq); 601 602 /* Set floor frequency to cpuinfo.min_freq */ 603 ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); 604 if (ret < 0) { 605 pr_err("Failed to set floor frequency to %s\n", buf); 606 return ret; 607 } 608 609 memset(buf, 0, PAGE_SIZE); 610 ret = show_amd_pstate_floor_freq(policy, buf); 611 if (ret < 0) 612 return ret; 613 614 strreplace(buf, '\n', '\0'); 615 ret = kstrtou32(buf, 0, &floor_freq); 616 if (ret) 617 return ret; 618 619 /* Confirm sysfs reflects the change correctly. */ 620 if (floor_freq != policy->cpuinfo.min_freq) { 621 pr_err("Floor frequency value mismatch: %u != %u\n", 622 floor_freq, policy->cpuinfo.min_freq); 623 return -EINVAL; 624 } 625 626 memset(buf, 0, PAGE_SIZE); 627 snprintf(buf, PAGE_SIZE, "%u", orig_floor_freq); 628 629 /* Restore the original value. */ 630 ret = store_amd_pstate_floor_freq(policy, buf, strlen(buf)); 631 if (ret < 0) { 632 pr_err("Failed to restore floor frequency to %s\n", buf); 633 return ret; 634 } 635 636 return 0; 637 } 638 639 static int __init amd_pstate_ut_init(void) 640 { 641 u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases); 642 enum amd_pstate_mode mode = amd_pstate_get_status(); 643 644 /* don't test if no running amd-pstate driver */ 645 if (mode == AMD_PSTATE_UNDEFINED || mode == AMD_PSTATE_DISABLE) 646 return -EOPNOTSUPP; 647 648 for (i = 0; i < arr_size; i++) { 649 int ret; 650 651 if (test_list && *test_list && 652 !test_in_list(test_list, amd_pstate_ut_cases[i].name)) 653 continue; 654 655 ret = amd_pstate_ut_cases[i].func(i); 656 657 if (ret) { 658 /* Platform does not support the feature being tested. */ 659 if (ret == -EOPNOTSUPP) { 660 pr_err("%-4d %-20s\t skipped!\n", i+1, amd_pstate_ut_cases[i].name); 661 continue; 662 } 663 pr_err("%-4d %-20s\t fail: %d!\n", i+1, amd_pstate_ut_cases[i].name, ret); 664 } else { 665 pr_info("%-4d %-20s\t success!\n", i+1, amd_pstate_ut_cases[i].name); 666 } 667 } 668 669 return 0; 670 } 671 672 static void __exit amd_pstate_ut_exit(void) 673 { 674 } 675 676 module_init(amd_pstate_ut_init); 677 module_exit(amd_pstate_ut_exit); 678 679 MODULE_AUTHOR("Meng Li <li.meng@amd.com>"); 680 MODULE_DESCRIPTION("AMD P-state driver Test module"); 681 MODULE_LICENSE("GPL"); 682