Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

cpufreq: amd-pstate: initialize core precision boost state

The "Core Performance Boost (CPB) feature, when enabled in the BIOS,
allows the OS to control the highest performance for each individual
core. The active, passive and the guided modes of the amd-pstate driver
do support controlling the core frequency boost when this BIOS feature
is enabled. Additionally, the amd-pstate driver provides a sysfs
interface allowing the user to activate/deactivate this core performance
boost feature at runtime.

Add support for the set_boost callback in the active mode driver to
enable boost control via the cpufreq core. This ensures a consistent
boost control interface across all pstate modes, including passive
mode, guided mode, and active mode.

With this addition, all three pstate modes can support the same boost
control interface with unique interface and global CPB control. Each
CPU also supports individual boost control, allowing global CPB to
change all cores' boost states simultaneously. Specific CPUs can
update their boost states separately, ensuring all cores' boost
states are synchronized.

Cc: Oleksandr Natalenko <oleksandr@natalenko.name>
Closes: https://bugzilla.kernel.org/show_bug.cgi?id=217931
Signed-off-by: Perry Yuan <Perry.Yuan@amd.com>
Co-developed-by: Mario Limonciello <mario.limonciello@amd.com>
Reviewed-by: Gautham R. Shenoy <gautham.shenoy@amd.com>
Link: https://lore.kernel.org/r/20240626042733.3747-3-mario.limonciello@amd.com
Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>

authored by

Perry Yuan and committed by
Mario Limonciello
c8c68c38 4f460bff

+98 -24
+97 -24
drivers/cpufreq/amd-pstate.c
··· 679 679 cpufreq_cpu_put(policy); 680 680 } 681 681 682 + static int amd_pstate_cpu_boost_update(struct cpufreq_policy *policy, bool on) 683 + { 684 + struct amd_cpudata *cpudata = policy->driver_data; 685 + struct cppc_perf_ctrls perf_ctrls; 686 + u32 highest_perf, nominal_perf, nominal_freq, max_freq; 687 + int ret; 688 + 689 + highest_perf = READ_ONCE(cpudata->highest_perf); 690 + nominal_perf = READ_ONCE(cpudata->nominal_perf); 691 + nominal_freq = READ_ONCE(cpudata->nominal_freq); 692 + max_freq = READ_ONCE(cpudata->max_freq); 693 + 694 + if (boot_cpu_has(X86_FEATURE_CPPC)) { 695 + u64 value = READ_ONCE(cpudata->cppc_req_cached); 696 + 697 + value &= ~GENMASK_ULL(7, 0); 698 + value |= on ? highest_perf : nominal_perf; 699 + WRITE_ONCE(cpudata->cppc_req_cached, value); 700 + 701 + wrmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, value); 702 + } else { 703 + perf_ctrls.max_perf = on ? highest_perf : nominal_perf; 704 + ret = cppc_set_perf(cpudata->cpu, &perf_ctrls); 705 + if (ret) { 706 + cpufreq_cpu_release(policy); 707 + pr_debug("Failed to set max perf on CPU:%d. ret:%d\n", 708 + cpudata->cpu, ret); 709 + return ret; 710 + } 711 + } 712 + 713 + if (on) 714 + policy->cpuinfo.max_freq = max_freq; 715 + else if (policy->cpuinfo.max_freq > nominal_freq * 1000) 716 + policy->cpuinfo.max_freq = nominal_freq * 1000; 717 + 718 + policy->max = policy->cpuinfo.max_freq; 719 + 720 + if (cppc_state == AMD_PSTATE_PASSIVE) { 721 + ret = freq_qos_update_request(&cpudata->req[1], policy->cpuinfo.max_freq); 722 + if (ret < 0) 723 + pr_debug("Failed to update freq constraint: CPU%d\n", cpudata->cpu); 724 + } 725 + 726 + return ret < 0 ? ret : 0; 727 + } 728 + 682 729 static int amd_pstate_set_boost(struct cpufreq_policy *policy, int state) 683 730 { 684 731 struct amd_cpudata *cpudata = policy->driver_data; ··· 733 686 734 687 if (!cpudata->boost_supported) { 735 688 pr_err("Boost mode is not supported by this processor or SBIOS\n"); 736 - return -EINVAL; 689 + return -EOPNOTSUPP; 737 690 } 691 + mutex_lock(&amd_pstate_driver_lock); 692 + ret = amd_pstate_cpu_boost_update(policy, state); 693 + WRITE_ONCE(cpudata->boost_state, !ret ? state : false); 694 + policy->boost_enabled = !ret ? state : false; 695 + refresh_frequency_limits(policy); 696 + mutex_unlock(&amd_pstate_driver_lock); 738 697 739 - if (state) 740 - policy->cpuinfo.max_freq = cpudata->max_freq; 741 - else 742 - policy->cpuinfo.max_freq = cpudata->nominal_freq * 1000; 743 - 744 - policy->max = policy->cpuinfo.max_freq; 745 - 746 - ret = freq_qos_update_request(&cpudata->req[1], 747 - policy->cpuinfo.max_freq); 748 - if (ret < 0) 749 - return ret; 750 - 751 - return 0; 698 + return ret; 752 699 } 753 700 754 - static void amd_pstate_boost_init(struct amd_cpudata *cpudata) 701 + static int amd_pstate_init_boost_support(struct amd_cpudata *cpudata) 755 702 { 756 - u32 highest_perf, nominal_perf; 703 + u64 boost_val; 704 + int ret = -1; 757 705 758 - highest_perf = READ_ONCE(cpudata->highest_perf); 759 - nominal_perf = READ_ONCE(cpudata->nominal_perf); 706 + /* 707 + * If platform has no CPB support or disable it, initialize current driver 708 + * boost_enabled state to be false, it is not an error for cpufreq core to handle. 709 + */ 710 + if (!cpu_feature_enabled(X86_FEATURE_CPB)) { 711 + pr_debug_once("Boost CPB capabilities not present in the processor\n"); 712 + ret = 0; 713 + goto exit_err; 714 + } 760 715 761 - if (highest_perf <= nominal_perf) 762 - return; 763 - 764 - cpudata->boost_supported = true; 716 + /* at least one CPU supports CPB, even if others fail later on to set up */ 765 717 current_pstate_driver->boost_enabled = true; 718 + 719 + ret = rdmsrl_on_cpu(cpudata->cpu, MSR_K7_HWCR, &boost_val); 720 + if (ret) { 721 + pr_err_once("failed to read initial CPU boost state!\n"); 722 + ret = -EIO; 723 + goto exit_err; 724 + } 725 + 726 + if (!(boost_val & MSR_K7_HWCR_CPB_DIS)) 727 + cpudata->boost_supported = true; 728 + 729 + return 0; 730 + 731 + exit_err: 732 + cpudata->boost_supported = false; 733 + return ret; 766 734 } 767 735 768 736 static void amd_perf_ctl_reset(unsigned int cpu) ··· 1030 968 if (ret) 1031 969 goto free_cpudata1; 1032 970 971 + ret = amd_pstate_init_boost_support(cpudata); 972 + if (ret) 973 + goto free_cpudata1; 974 + 1033 975 min_freq = READ_ONCE(cpudata->min_freq); 1034 976 max_freq = READ_ONCE(cpudata->max_freq); 1035 977 ··· 1045 979 1046 980 policy->cpuinfo.min_freq = min_freq; 1047 981 policy->cpuinfo.max_freq = max_freq; 982 + 983 + policy->boost_enabled = READ_ONCE(cpudata->boost_supported); 1048 984 1049 985 /* It will be updated by governor */ 1050 986 policy->cur = policy->cpuinfo.min_freq; ··· 1073 1005 1074 1006 policy->driver_data = cpudata; 1075 1007 1076 - amd_pstate_boost_init(cpudata); 1077 1008 if (!current_pstate_driver->adjust_perf) 1078 1009 current_pstate_driver->adjust_perf = amd_pstate_adjust_perf; 1079 1010 ··· 1487 1420 if (ret) 1488 1421 goto free_cpudata1; 1489 1422 1423 + ret = amd_pstate_init_boost_support(cpudata); 1424 + if (ret) 1425 + goto free_cpudata1; 1426 + 1490 1427 min_freq = READ_ONCE(cpudata->min_freq); 1491 1428 max_freq = READ_ONCE(cpudata->max_freq); 1492 1429 ··· 1505 1434 1506 1435 policy->min = policy->cpuinfo.min_freq; 1507 1436 policy->max = policy->cpuinfo.max_freq; 1437 + 1438 + policy->boost_enabled = READ_ONCE(cpudata->boost_supported); 1508 1439 1509 1440 /* 1510 1441 * Set the policy to provide a valid fallback value in case ··· 1529 1456 return ret; 1530 1457 WRITE_ONCE(cpudata->cppc_cap1_cached, value); 1531 1458 } 1532 - amd_pstate_boost_init(cpudata); 1533 1459 1534 1460 return 0; 1535 1461 ··· 1790 1718 .suspend = amd_pstate_epp_suspend, 1791 1719 .resume = amd_pstate_epp_resume, 1792 1720 .update_limits = amd_pstate_update_limits, 1721 + .set_boost = amd_pstate_set_boost, 1793 1722 .name = "amd-pstate-epp", 1794 1723 .attr = amd_pstate_epp_attr, 1795 1724 };
+1
drivers/cpufreq/amd-pstate.h
··· 100 100 u64 cppc_cap1_cached; 101 101 bool suspended; 102 102 s16 epp_default; 103 + bool boost_state; 103 104 }; 104 105 105 106 #endif /* _LINUX_AMD_PSTATE_H */