Skip to content

Commit f3a0523

Browse files
Meng Lirafaeljw
authored andcommitted
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>
1 parent 12753d7 commit f3a0523

2 files changed

Lines changed: 127 additions & 8 deletions

File tree

drivers/cpufreq/amd-pstate.c

Lines changed: 123 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@
3737
#include <linux/uaccess.h>
3838
#include <linux/static_call.h>
3939
#include <linux/amd-pstate.h>
40+
#include <linux/topology.h>
4041

4142
#include <acpi/processor.h>
4243
#include <acpi/cppc_acpi.h>
@@ -49,6 +50,7 @@
4950

5051
#define AMD_PSTATE_TRANSITION_LATENCY 20000
5152
#define AMD_PSTATE_TRANSITION_DELAY 1000
53+
#define AMD_PSTATE_PREFCORE_THRESHOLD 166
5254

5355
/*
5456
* TODO: We need more time to fine tune processors with shared memory solution
@@ -64,6 +66,7 @@ static struct cpufreq_driver amd_pstate_driver;
6466
static struct cpufreq_driver amd_pstate_epp_driver;
6567
static int cppc_state = AMD_PSTATE_UNDEFINED;
6668
static bool cppc_enabled;
69+
static bool amd_pstate_prefcore = true;
6770

6871
/*
6972
* AMD Energy Preference Performance (EPP)
@@ -297,13 +300,14 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
297300
if (ret)
298301
return ret;
299302

300-
/*
301-
* TODO: Introduce AMD specific power feature.
302-
*
303-
* CPPC entry doesn't indicate the highest performance in some ASICs.
303+
/* For platforms that do not support the preferred core feature, the
304+
* highest_pef may be configured with 166 or 255, to avoid max frequency
305+
* calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as
306+
* the default max perf.
304307
*/
305-
highest_perf = amd_get_highest_perf();
306-
if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1))
308+
if (cpudata->hw_prefcore)
309+
highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
310+
else
307311
highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
308312

309313
WRITE_ONCE(cpudata->highest_perf, highest_perf);
@@ -324,8 +328,9 @@ static int cppc_init_perf(struct amd_cpudata *cpudata)
324328
if (ret)
325329
return ret;
326330

327-
highest_perf = amd_get_highest_perf();
328-
if (highest_perf > cppc_perf.highest_perf)
331+
if (cpudata->hw_prefcore)
332+
highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
333+
else
329334
highest_perf = cppc_perf.highest_perf;
330335

331336
WRITE_ONCE(cpudata->highest_perf, highest_perf);
@@ -706,6 +711,80 @@ static void amd_perf_ctl_reset(unsigned int cpu)
706711
wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0);
707712
}
708713

714+
/*
715+
* Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks
716+
* due to locking, so queue the work for later.
717+
*/
718+
static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
719+
{
720+
sched_set_itmt_support();
721+
}
722+
static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);
723+
724+
/*
725+
* Get the highest performance register value.
726+
* @cpu: CPU from which to get highest performance.
727+
* @highest_perf: Return address.
728+
*
729+
* Return: 0 for success, -EIO otherwise.
730+
*/
731+
static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf)
732+
{
733+
int ret;
734+
735+
if (boot_cpu_has(X86_FEATURE_CPPC)) {
736+
u64 cap1;
737+
738+
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
739+
if (ret)
740+
return ret;
741+
WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
742+
} else {
743+
u64 cppc_highest_perf;
744+
745+
ret = cppc_get_highest_perf(cpu, &cppc_highest_perf);
746+
if (ret)
747+
return ret;
748+
WRITE_ONCE(*highest_perf, cppc_highest_perf);
749+
}
750+
751+
return (ret);
752+
}
753+
754+
#define CPPC_MAX_PERF U8_MAX
755+
756+
static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
757+
{
758+
int ret, prio;
759+
u32 highest_perf;
760+
761+
ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf);
762+
if (ret)
763+
return;
764+
765+
cpudata->hw_prefcore = true;
766+
/* check if CPPC preferred core feature is enabled*/
767+
if (highest_perf < CPPC_MAX_PERF)
768+
prio = (int)highest_perf;
769+
else {
770+
pr_debug("AMD CPPC preferred core is unsupported!\n");
771+
cpudata->hw_prefcore = false;
772+
return;
773+
}
774+
775+
if (!amd_pstate_prefcore)
776+
return;
777+
778+
/*
779+
* The priorities can be set regardless of whether or not
780+
* sched_set_itmt_support(true) has been called and it is valid to
781+
* update them at any time after it has been called.
782+
*/
783+
sched_set_itmt_core_prio(prio, cpudata->cpu);
784+
785+
schedule_work(&sched_prefcore_work);
786+
}
787+
709788
static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
710789
{
711790
int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
@@ -727,6 +806,8 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
727806

728807
cpudata->cpu = policy->cpu;
729808

809+
amd_pstate_init_prefcore(cpudata);
810+
730811
ret = amd_pstate_init_perf(cpudata);
731812
if (ret)
732813
goto free_cpudata1;
@@ -877,6 +958,17 @@ static ssize_t show_amd_pstate_highest_perf(struct cpufreq_policy *policy,
877958
return sysfs_emit(buf, "%u\n", perf);
878959
}
879960

961+
static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy,
962+
char *buf)
963+
{
964+
bool hw_prefcore;
965+
struct amd_cpudata *cpudata = policy->driver_data;
966+
967+
hw_prefcore = READ_ONCE(cpudata->hw_prefcore);
968+
969+
return sysfs_emit(buf, "%s\n", str_enabled_disabled(hw_prefcore));
970+
}
971+
880972
static ssize_t show_energy_performance_available_preferences(
881973
struct cpufreq_policy *policy, char *buf)
882974
{
@@ -1074,32 +1166,43 @@ static ssize_t status_store(struct device *a, struct device_attribute *b,
10741166
return ret < 0 ? ret : count;
10751167
}
10761168

1169+
static ssize_t prefcore_show(struct device *dev,
1170+
struct device_attribute *attr, char *buf)
1171+
{
1172+
return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore));
1173+
}
1174+
10771175
cpufreq_freq_attr_ro(amd_pstate_max_freq);
10781176
cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
10791177

10801178
cpufreq_freq_attr_ro(amd_pstate_highest_perf);
1179+
cpufreq_freq_attr_ro(amd_pstate_hw_prefcore);
10811180
cpufreq_freq_attr_rw(energy_performance_preference);
10821181
cpufreq_freq_attr_ro(energy_performance_available_preferences);
10831182
static DEVICE_ATTR_RW(status);
1183+
static DEVICE_ATTR_RO(prefcore);
10841184

10851185
static struct freq_attr *amd_pstate_attr[] = {
10861186
&amd_pstate_max_freq,
10871187
&amd_pstate_lowest_nonlinear_freq,
10881188
&amd_pstate_highest_perf,
1189+
&amd_pstate_hw_prefcore,
10891190
NULL,
10901191
};
10911192

10921193
static struct freq_attr *amd_pstate_epp_attr[] = {
10931194
&amd_pstate_max_freq,
10941195
&amd_pstate_lowest_nonlinear_freq,
10951196
&amd_pstate_highest_perf,
1197+
&amd_pstate_hw_prefcore,
10961198
&energy_performance_preference,
10971199
&energy_performance_available_preferences,
10981200
NULL,
10991201
};
11001202

11011203
static struct attribute *pstate_global_attributes[] = {
11021204
&dev_attr_status.attr,
1205+
&dev_attr_prefcore.attr,
11031206
NULL
11041207
};
11051208

@@ -1151,6 +1254,8 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
11511254
cpudata->cpu = policy->cpu;
11521255
cpudata->epp_policy = 0;
11531256

1257+
amd_pstate_init_prefcore(cpudata);
1258+
11541259
ret = amd_pstate_init_perf(cpudata);
11551260
if (ret)
11561261
goto free_cpudata1;
@@ -1567,7 +1672,17 @@ static int __init amd_pstate_param(char *str)
15671672

15681673
return amd_pstate_set_driver(mode_idx);
15691674
}
1675+
1676+
static int __init amd_prefcore_param(char *str)
1677+
{
1678+
if (!strcmp(str, "disable"))
1679+
amd_pstate_prefcore = false;
1680+
1681+
return 0;
1682+
}
1683+
15701684
early_param("amd_pstate", amd_pstate_param);
1685+
early_param("amd_prefcore", amd_prefcore_param);
15711686

15721687
MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
15731688
MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");

include/linux/amd-pstate.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -52,6 +52,9 @@ struct amd_aperf_mperf {
5252
* @prev: Last Aperf/Mperf/tsc count value read from register
5353
* @freq: current cpu frequency value
5454
* @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.
5558
* @epp_policy: Last saved policy used to set energy-performance preference
5659
* @epp_cached: Cached CPPC energy-performance preference value
5760
* @policy: Cpufreq policy value
@@ -85,6 +88,7 @@ struct amd_cpudata {
8588

8689
u64 freq;
8790
bool boost_supported;
91+
bool hw_prefcore;
8892

8993
/* EPP feature related attributes*/
9094
s16 epp_policy;

0 commit comments

Comments
 (0)