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

cpufreq: amd-pstate: Enable amd-pstate preferred core support

amd-pstate driver utilizes the functions and data structures
provided by the ITMT architecture to enable the scheduler to
favor scheduling on cores which can be get a higher frequency
with lower voltage. We call it amd-pstate preferrred core.

Here sched_set_itmt_core_prio() is called to set priorities and
sched_set_itmt_support() is called to enable ITMT feature.
amd-pstate driver uses the highest performance value to indicate
the priority of CPU. The higher value has a higher priority.

The initial core rankings are set up by amd-pstate when the
system boots.

Add a variable hw_prefcore in cpudata structure. It will check
if the processor and power firmware support preferred core
feature.

Add one new early parameter `disable` to allow user to disable
the preferred core.

Only when hardware supports preferred core and user set `enabled`
in early parameter, amd pstate driver supports preferred core featue.

Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
Reviewed-by: Huang Rui <ray.huang@amd.com>
Reviewed-by: Wyes Karny <wyes.karny@amd.com>
Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
Co-developed-by: Perry Yuan <Perry.Yuan@amd.com>
Signed-off-by: Perry Yuan <Perry.Yuan@amd.com>
Signed-off-by: Meng Li <li.meng@amd.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>

authored by

Meng Li and committed by
Rafael J. Wysocki
f3a05239 12753d71

+127 -8
+123 -8
drivers/cpufreq/amd-pstate.c
··· 37 37 #include <linux/uaccess.h> 38 38 #include <linux/static_call.h> 39 39 #include <linux/amd-pstate.h> 40 + #include <linux/topology.h> 40 41 41 42 #include <acpi/processor.h> 42 43 #include <acpi/cppc_acpi.h> ··· 50 49 51 50 #define AMD_PSTATE_TRANSITION_LATENCY 20000 52 51 #define AMD_PSTATE_TRANSITION_DELAY 1000 52 + #define AMD_PSTATE_PREFCORE_THRESHOLD 166 53 53 54 54 /* 55 55 * TODO: We need more time to fine tune processors with shared memory solution ··· 66 64 static struct cpufreq_driver amd_pstate_epp_driver; 67 65 static int cppc_state = AMD_PSTATE_UNDEFINED; 68 66 static bool cppc_enabled; 67 + static bool amd_pstate_prefcore = true; 69 68 70 69 /* 71 70 * AMD Energy Preference Performance (EPP) ··· 300 297 if (ret) 301 298 return ret; 302 299 303 - /* 304 - * TODO: Introduce AMD specific power feature. 305 - * 306 - * CPPC entry doesn't indicate the highest performance in some ASICs. 300 + /* For platforms that do not support the preferred core feature, the 301 + * highest_pef may be configured with 166 or 255, to avoid max frequency 302 + * calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as 303 + * the default max perf. 307 304 */ 308 - highest_perf = amd_get_highest_perf(); 309 - if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1)) 305 + if (cpudata->hw_prefcore) 306 + highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD; 307 + else 310 308 highest_perf = AMD_CPPC_HIGHEST_PERF(cap1); 311 309 312 310 WRITE_ONCE(cpudata->highest_perf, highest_perf); ··· 328 324 if (ret) 329 325 return ret; 330 326 331 - highest_perf = amd_get_highest_perf(); 332 - if (highest_perf > cppc_perf.highest_perf) 327 + if (cpudata->hw_prefcore) 328 + highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD; 329 + else 333 330 highest_perf = cppc_perf.highest_perf; 334 331 335 332 WRITE_ONCE(cpudata->highest_perf, highest_perf); ··· 711 706 wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0); 712 707 } 713 708 709 + /* 710 + * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks 711 + * due to locking, so queue the work for later. 712 + */ 713 + static void amd_pstste_sched_prefcore_workfn(struct work_struct *work) 714 + { 715 + sched_set_itmt_support(); 716 + } 717 + static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn); 718 + 719 + /* 720 + * Get the highest performance register value. 721 + * @cpu: CPU from which to get highest performance. 722 + * @highest_perf: Return address. 723 + * 724 + * Return: 0 for success, -EIO otherwise. 725 + */ 726 + static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf) 727 + { 728 + int ret; 729 + 730 + if (boot_cpu_has(X86_FEATURE_CPPC)) { 731 + u64 cap1; 732 + 733 + ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1); 734 + if (ret) 735 + return ret; 736 + WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1)); 737 + } else { 738 + u64 cppc_highest_perf; 739 + 740 + ret = cppc_get_highest_perf(cpu, &cppc_highest_perf); 741 + if (ret) 742 + return ret; 743 + WRITE_ONCE(*highest_perf, cppc_highest_perf); 744 + } 745 + 746 + return (ret); 747 + } 748 + 749 + #define CPPC_MAX_PERF U8_MAX 750 + 751 + static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata) 752 + { 753 + int ret, prio; 754 + u32 highest_perf; 755 + 756 + ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf); 757 + if (ret) 758 + return; 759 + 760 + cpudata->hw_prefcore = true; 761 + /* check if CPPC preferred core feature is enabled*/ 762 + if (highest_perf < CPPC_MAX_PERF) 763 + prio = (int)highest_perf; 764 + else { 765 + pr_debug("AMD CPPC preferred core is unsupported!\n"); 766 + cpudata->hw_prefcore = false; 767 + return; 768 + } 769 + 770 + if (!amd_pstate_prefcore) 771 + return; 772 + 773 + /* 774 + * The priorities can be set regardless of whether or not 775 + * sched_set_itmt_support(true) has been called and it is valid to 776 + * update them at any time after it has been called. 777 + */ 778 + sched_set_itmt_core_prio(prio, cpudata->cpu); 779 + 780 + schedule_work(&sched_prefcore_work); 781 + } 782 + 714 783 static int amd_pstate_cpu_init(struct cpufreq_policy *policy) 715 784 { 716 785 int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret; ··· 805 726 return -ENOMEM; 806 727 807 728 cpudata->cpu = policy->cpu; 729 + 730 + amd_pstate_init_prefcore(cpudata); 808 731 809 732 ret = amd_pstate_init_perf(cpudata); 810 733 if (ret) ··· 956 875 perf = READ_ONCE(cpudata->highest_perf); 957 876 958 877 return sysfs_emit(buf, "%u\n", perf); 878 + } 879 + 880 + static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy, 881 + char *buf) 882 + { 883 + bool hw_prefcore; 884 + struct amd_cpudata *cpudata = policy->driver_data; 885 + 886 + hw_prefcore = READ_ONCE(cpudata->hw_prefcore); 887 + 888 + return sysfs_emit(buf, "%s\n", str_enabled_disabled(hw_prefcore)); 959 889 } 960 890 961 891 static ssize_t show_energy_performance_available_preferences( ··· 1166 1074 return ret < 0 ? ret : count; 1167 1075 } 1168 1076 1077 + static ssize_t prefcore_show(struct device *dev, 1078 + struct device_attribute *attr, char *buf) 1079 + { 1080 + return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore)); 1081 + } 1082 + 1169 1083 cpufreq_freq_attr_ro(amd_pstate_max_freq); 1170 1084 cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq); 1171 1085 1172 1086 cpufreq_freq_attr_ro(amd_pstate_highest_perf); 1087 + cpufreq_freq_attr_ro(amd_pstate_hw_prefcore); 1173 1088 cpufreq_freq_attr_rw(energy_performance_preference); 1174 1089 cpufreq_freq_attr_ro(energy_performance_available_preferences); 1175 1090 static DEVICE_ATTR_RW(status); 1091 + static DEVICE_ATTR_RO(prefcore); 1176 1092 1177 1093 static struct freq_attr *amd_pstate_attr[] = { 1178 1094 &amd_pstate_max_freq, 1179 1095 &amd_pstate_lowest_nonlinear_freq, 1180 1096 &amd_pstate_highest_perf, 1097 + &amd_pstate_hw_prefcore, 1181 1098 NULL, 1182 1099 }; 1183 1100 ··· 1194 1093 &amd_pstate_max_freq, 1195 1094 &amd_pstate_lowest_nonlinear_freq, 1196 1095 &amd_pstate_highest_perf, 1096 + &amd_pstate_hw_prefcore, 1197 1097 &energy_performance_preference, 1198 1098 &energy_performance_available_preferences, 1199 1099 NULL, ··· 1202 1100 1203 1101 static struct attribute *pstate_global_attributes[] = { 1204 1102 &dev_attr_status.attr, 1103 + &dev_attr_prefcore.attr, 1205 1104 NULL 1206 1105 }; 1207 1106 ··· 1253 1150 1254 1151 cpudata->cpu = policy->cpu; 1255 1152 cpudata->epp_policy = 0; 1153 + 1154 + amd_pstate_init_prefcore(cpudata); 1256 1155 1257 1156 ret = amd_pstate_init_perf(cpudata); 1258 1157 if (ret) ··· 1672 1567 1673 1568 return amd_pstate_set_driver(mode_idx); 1674 1569 } 1570 + 1571 + static int __init amd_prefcore_param(char *str) 1572 + { 1573 + if (!strcmp(str, "disable")) 1574 + amd_pstate_prefcore = false; 1575 + 1576 + return 0; 1577 + } 1578 + 1675 1579 early_param("amd_pstate", amd_pstate_param); 1580 + early_param("amd_prefcore", amd_prefcore_param); 1676 1581 1677 1582 MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>"); 1678 1583 MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
+4
include/linux/amd-pstate.h
··· 52 52 * @prev: Last Aperf/Mperf/tsc count value read from register 53 53 * @freq: current cpu frequency value 54 54 * @boost_supported: check whether the Processor or SBIOS supports boost mode 55 + * @hw_prefcore: check whether HW supports preferred core featue. 56 + * Only when hw_prefcore and early prefcore param are true, 57 + * AMD P-State driver supports preferred core featue. 55 58 * @epp_policy: Last saved policy used to set energy-performance preference 56 59 * @epp_cached: Cached CPPC energy-performance preference value 57 60 * @policy: Cpufreq policy value ··· 88 85 89 86 u64 freq; 90 87 bool boost_supported; 88 + bool hw_prefcore; 91 89 92 90 /* EPP feature related attributes*/ 93 91 s16 epp_policy;