--- /dev/null
+From 12753d71e8c5c3e716cedba23ddeed508da0bdc4 Mon Sep 17 00:00:00 2001
+From: Meng Li <li.meng@amd.com>
+Date: Fri, 19 Jan 2024 17:04:57 +0800
+Subject: ACPI: CPPC: Add helper to get the highest performance value
+
+From: Meng Li <li.meng@amd.com>
+
+commit 12753d71e8c5c3e716cedba23ddeed508da0bdc4 upstream.
+
+Add support for getting the highest performance to the
+generic CPPC driver. This enables downstream drivers
+such as amd-pstate to discover and use these values.
+
+Refer to Chapter 8.4.6.1.1.1. Highest Performance of ACPI
+Specification 6.5 for details on continuous performance control
+of CPPC (linked below).
+
+Tested-by: Oleksandr Natalenko <oleksandr@natalenko.name>
+Reviewed-by: Mario Limonciello <mario.limonciello@amd.com>
+Reviewed-by: Wyes Karny <wyes.karny@amd.com>
+Reviewed-by: Perry Yuan <perry.yuan@amd.com>
+Acked-by: Huang Rui <ray.huang@amd.com>
+Signed-off-by: Meng Li <li.meng@amd.com>
+Link: https://uefi.org/specs/ACPI/6.5/08_Processor_Configuration_and_Control.html?highlight=cppc#highest-performance
+[ rjw: Subject and changelog edits ]
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/acpi/cppc_acpi.c | 13 +++++++++++++
+ include/acpi/cppc_acpi.h | 5 +++++
+ 2 files changed, 18 insertions(+)
+
+--- a/drivers/acpi/cppc_acpi.c
++++ b/drivers/acpi/cppc_acpi.c
+@@ -1197,6 +1197,19 @@ int cppc_get_nominal_perf(int cpunum, u6
+ }
+
+ /**
++ * cppc_get_highest_perf - Get the highest performance register value.
++ * @cpunum: CPU from which to get highest performance.
++ * @highest_perf: Return address.
++ *
++ * Return: 0 for success, -EIO otherwise.
++ */
++int cppc_get_highest_perf(int cpunum, u64 *highest_perf)
++{
++ return cppc_get_perf(cpunum, HIGHEST_PERF, highest_perf);
++}
++EXPORT_SYMBOL_GPL(cppc_get_highest_perf);
++
++/**
+ * cppc_get_epp_perf - Get the epp register value.
+ * @cpunum: CPU from which to get epp preference value.
+ * @epp_perf: Return address.
+--- a/include/acpi/cppc_acpi.h
++++ b/include/acpi/cppc_acpi.h
+@@ -139,6 +139,7 @@ struct cppc_cpudata {
+ #ifdef CONFIG_ACPI_CPPC_LIB
+ extern int cppc_get_desired_perf(int cpunum, u64 *desired_perf);
+ extern int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf);
++extern int cppc_get_highest_perf(int cpunum, u64 *highest_perf);
+ extern int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs);
+ extern int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls);
+ extern int cppc_set_enable(int cpu, bool enable);
+@@ -165,6 +166,10 @@ static inline int cppc_get_nominal_perf(
+ {
+ return -ENOTSUPP;
+ }
++static inline int cppc_get_highest_perf(int cpunum, u64 *highest_perf)
++{
++ return -ENOTSUPP;
++}
+ static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
+ {
+ return -ENOTSUPP;
--- /dev/null
+From f3a052391822b772b4e27f2594526cf1eb103cab Mon Sep 17 00:00:00 2001
+From: Meng Li <li.meng@amd.com>
+Date: Fri, 19 Jan 2024 17:04:58 +0800
+Subject: cpufreq: amd-pstate: Enable amd-pstate preferred core support
+
+From: Meng Li <li.meng@amd.com>
+
+commit f3a052391822b772b4e27f2594526cf1eb103cab upstream.
+
+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>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/cpufreq/amd-pstate.c | 131 ++++++++++++++++++++++++++++++++++++++++---
+ include/linux/amd-pstate.h | 4 +
+ 2 files changed, 127 insertions(+), 8 deletions(-)
+
+--- a/drivers/cpufreq/amd-pstate.c
++++ b/drivers/cpufreq/amd-pstate.c
+@@ -37,6 +37,7 @@
+ #include <linux/uaccess.h>
+ #include <linux/static_call.h>
+ #include <linux/amd-pstate.h>
++#include <linux/topology.h>
+
+ #include <acpi/processor.h>
+ #include <acpi/cppc_acpi.h>
+@@ -49,6 +50,7 @@
+
+ #define AMD_PSTATE_TRANSITION_LATENCY 20000
+ #define AMD_PSTATE_TRANSITION_DELAY 1000
++#define AMD_PSTATE_PREFCORE_THRESHOLD 166
+
+ /*
+ * TODO: We need more time to fine tune processors with shared memory solution
+@@ -64,6 +66,7 @@ static struct cpufreq_driver amd_pstate_
+ static struct cpufreq_driver amd_pstate_epp_driver;
+ static int cppc_state = AMD_PSTATE_UNDEFINED;
+ static bool cppc_enabled;
++static bool amd_pstate_prefcore = true;
+
+ /*
+ * AMD Energy Preference Performance (EPP)
+@@ -320,13 +323,14 @@ static int pstate_init_perf(struct amd_c
+ if (ret)
+ return ret;
+
+- /*
+- * TODO: Introduce AMD specific power feature.
+- *
+- * CPPC entry doesn't indicate the highest performance in some ASICs.
++ /* For platforms that do not support the preferred core feature, the
++ * highest_pef may be configured with 166 or 255, to avoid max frequency
++ * calculated wrongly. we take the AMD_CPPC_HIGHEST_PERF(cap1) value as
++ * the default max perf.
+ */
+- highest_perf = amd_get_highest_perf();
+- if (highest_perf > AMD_CPPC_HIGHEST_PERF(cap1))
++ if (cpudata->hw_prefcore)
++ highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
++ else
+ highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
+
+ WRITE_ONCE(cpudata->highest_perf, highest_perf);
+@@ -347,8 +351,9 @@ static int cppc_init_perf(struct amd_cpu
+ if (ret)
+ return ret;
+
+- highest_perf = amd_get_highest_perf();
+- if (highest_perf > cppc_perf.highest_perf)
++ if (cpudata->hw_prefcore)
++ highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
++ else
+ highest_perf = cppc_perf.highest_perf;
+
+ WRITE_ONCE(cpudata->highest_perf, highest_perf);
+@@ -709,6 +714,80 @@ static void amd_perf_ctl_reset(unsigned
+ wrmsrl_on_cpu(cpu, MSR_AMD_PERF_CTL, 0);
+ }
+
++/*
++ * Set amd-pstate preferred core enable can't be done directly from cpufreq callbacks
++ * due to locking, so queue the work for later.
++ */
++static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
++{
++ sched_set_itmt_support();
++}
++static DECLARE_WORK(sched_prefcore_work, amd_pstste_sched_prefcore_workfn);
++
++/*
++ * Get the highest performance register value.
++ * @cpu: CPU from which to get highest performance.
++ * @highest_perf: Return address.
++ *
++ * Return: 0 for success, -EIO otherwise.
++ */
++static int amd_pstate_get_highest_perf(int cpu, u32 *highest_perf)
++{
++ int ret;
++
++ if (boot_cpu_has(X86_FEATURE_CPPC)) {
++ u64 cap1;
++
++ ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &cap1);
++ if (ret)
++ return ret;
++ WRITE_ONCE(*highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
++ } else {
++ u64 cppc_highest_perf;
++
++ ret = cppc_get_highest_perf(cpu, &cppc_highest_perf);
++ if (ret)
++ return ret;
++ WRITE_ONCE(*highest_perf, cppc_highest_perf);
++ }
++
++ return (ret);
++}
++
++#define CPPC_MAX_PERF U8_MAX
++
++static void amd_pstate_init_prefcore(struct amd_cpudata *cpudata)
++{
++ int ret, prio;
++ u32 highest_perf;
++
++ ret = amd_pstate_get_highest_perf(cpudata->cpu, &highest_perf);
++ if (ret)
++ return;
++
++ cpudata->hw_prefcore = true;
++ /* check if CPPC preferred core feature is enabled*/
++ if (highest_perf < CPPC_MAX_PERF)
++ prio = (int)highest_perf;
++ else {
++ pr_debug("AMD CPPC preferred core is unsupported!\n");
++ cpudata->hw_prefcore = false;
++ return;
++ }
++
++ if (!amd_pstate_prefcore)
++ return;
++
++ /*
++ * The priorities can be set regardless of whether or not
++ * sched_set_itmt_support(true) has been called and it is valid to
++ * update them at any time after it has been called.
++ */
++ sched_set_itmt_core_prio(prio, cpudata->cpu);
++
++ schedule_work(&sched_prefcore_work);
++}
++
+ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
+ {
+ int min_freq, max_freq, nominal_freq, lowest_nonlinear_freq, ret;
+@@ -730,6 +809,8 @@ static int amd_pstate_cpu_init(struct cp
+
+ cpudata->cpu = policy->cpu;
+
++ amd_pstate_init_prefcore(cpudata);
++
+ ret = amd_pstate_init_perf(cpudata);
+ if (ret)
+ goto free_cpudata1;
+@@ -880,6 +961,17 @@ static ssize_t show_amd_pstate_highest_p
+ return sysfs_emit(buf, "%u\n", perf);
+ }
+
++static ssize_t show_amd_pstate_hw_prefcore(struct cpufreq_policy *policy,
++ char *buf)
++{
++ bool hw_prefcore;
++ struct amd_cpudata *cpudata = policy->driver_data;
++
++ hw_prefcore = READ_ONCE(cpudata->hw_prefcore);
++
++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(hw_prefcore));
++}
++
+ static ssize_t show_energy_performance_available_preferences(
+ struct cpufreq_policy *policy, char *buf)
+ {
+@@ -1077,18 +1169,27 @@ static ssize_t status_store(struct devic
+ return ret < 0 ? ret : count;
+ }
+
++static ssize_t prefcore_show(struct device *dev,
++ struct device_attribute *attr, char *buf)
++{
++ return sysfs_emit(buf, "%s\n", str_enabled_disabled(amd_pstate_prefcore));
++}
++
+ cpufreq_freq_attr_ro(amd_pstate_max_freq);
+ cpufreq_freq_attr_ro(amd_pstate_lowest_nonlinear_freq);
+
+ cpufreq_freq_attr_ro(amd_pstate_highest_perf);
++cpufreq_freq_attr_ro(amd_pstate_hw_prefcore);
+ cpufreq_freq_attr_rw(energy_performance_preference);
+ cpufreq_freq_attr_ro(energy_performance_available_preferences);
+ static DEVICE_ATTR_RW(status);
++static DEVICE_ATTR_RO(prefcore);
+
+ static struct freq_attr *amd_pstate_attr[] = {
+ &amd_pstate_max_freq,
+ &amd_pstate_lowest_nonlinear_freq,
+ &amd_pstate_highest_perf,
++ &amd_pstate_hw_prefcore,
+ NULL,
+ };
+
+@@ -1096,6 +1197,7 @@ static struct freq_attr *amd_pstate_epp_
+ &amd_pstate_max_freq,
+ &amd_pstate_lowest_nonlinear_freq,
+ &amd_pstate_highest_perf,
++ &amd_pstate_hw_prefcore,
+ &energy_performance_preference,
+ &energy_performance_available_preferences,
+ NULL,
+@@ -1103,6 +1205,7 @@ static struct freq_attr *amd_pstate_epp_
+
+ static struct attribute *pstate_global_attributes[] = {
+ &dev_attr_status.attr,
++ &dev_attr_prefcore.attr,
+ NULL
+ };
+
+@@ -1154,6 +1257,8 @@ static int amd_pstate_epp_cpu_init(struc
+ cpudata->cpu = policy->cpu;
+ cpudata->epp_policy = 0;
+
++ amd_pstate_init_prefcore(cpudata);
++
+ ret = amd_pstate_init_perf(cpudata);
+ if (ret)
+ goto free_cpudata1;
+@@ -1577,7 +1682,17 @@ static int __init amd_pstate_param(char
+
+ return amd_pstate_set_driver(mode_idx);
+ }
++
++static int __init amd_prefcore_param(char *str)
++{
++ if (!strcmp(str, "disable"))
++ amd_pstate_prefcore = false;
++
++ return 0;
++}
++
+ early_param("amd_pstate", amd_pstate_param);
++early_param("amd_prefcore", amd_prefcore_param);
+
+ MODULE_AUTHOR("Huang Rui <ray.huang@amd.com>");
+ MODULE_DESCRIPTION("AMD Processor P-state Frequency Driver");
+--- a/include/linux/amd-pstate.h
++++ b/include/linux/amd-pstate.h
+@@ -52,6 +52,9 @@ struct amd_aperf_mperf {
+ * @prev: Last Aperf/Mperf/tsc count value read from register
+ * @freq: current cpu frequency value
+ * @boost_supported: check whether the Processor or SBIOS supports boost mode
++ * @hw_prefcore: check whether HW supports preferred core featue.
++ * Only when hw_prefcore and early prefcore param are true,
++ * AMD P-State driver supports preferred core featue.
+ * @epp_policy: Last saved policy used to set energy-performance preference
+ * @epp_cached: Cached CPPC energy-performance preference value
+ * @policy: Cpufreq policy value
+@@ -85,6 +88,7 @@ struct amd_cpudata {
+
+ u64 freq;
+ bool boost_supported;
++ bool hw_prefcore;
+
+ /* EPP feature related attributes*/
+ s16 epp_policy;
--- /dev/null
+From bf202e654bfa57fb8cf9d93d4c6855890b70b9c4 Mon Sep 17 00:00:00 2001
+From: Perry Yuan <perry.yuan@amd.com>
+Date: Wed, 8 May 2024 13:47:03 +0800
+Subject: cpufreq: amd-pstate: fix the highest frequency issue which limits performance
+
+From: Perry Yuan <perry.yuan@amd.com>
+
+commit bf202e654bfa57fb8cf9d93d4c6855890b70b9c4 upstream.
+
+To address the performance drop issue, an optimization has been
+implemented. The incorrect highest performance value previously set by the
+low-level power firmware for AMD CPUs with Family ID 0x19 and Model ID
+ranging from 0x70 to 0x7F series has been identified as the cause.
+
+To resolve this, a check has been implemented to accurately determine the
+CPU family and model ID. The correct highest performance value is now set
+and the performance drop caused by the incorrect highest performance value
+are eliminated.
+
+Before the fix, the highest frequency was set to 4200MHz, now it is set
+to 4971MHz which is correct.
+
+CPU NODE SOCKET CORE L1d:L1i:L2:L3 ONLINE MAXMHZ MINMHZ MHZ
+ 0 0 0 0 0:0:0:0 yes 4971.0000 400.0000 400.0000
+ 1 0 0 0 0:0:0:0 yes 4971.0000 400.0000 400.0000
+ 2 0 0 1 1:1:1:0 yes 4971.0000 400.0000 4865.8140
+ 3 0 0 1 1:1:1:0 yes 4971.0000 400.0000 400.0000
+
+Fixes: f3a052391822 ("cpufreq: amd-pstate: Enable amd-pstate preferred core support")
+Closes: https://bugzilla.kernel.org/show_bug.cgi?id=218759
+Signed-off-by: Perry Yuan <perry.yuan@amd.com>
+Co-developed-by: Mario Limonciello <mario.limonciello@amd.com>
+Signed-off-by: Mario Limonciello <mario.limonciello@amd.com>
+Tested-by: Gaha Bana <gahabana@gmail.com>
+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
+Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org>
+---
+ drivers/cpufreq/amd-pstate.c | 22 +++++++++++++++++++---
+ 1 file changed, 19 insertions(+), 3 deletions(-)
+
+--- a/drivers/cpufreq/amd-pstate.c
++++ b/drivers/cpufreq/amd-pstate.c
+@@ -50,7 +50,8 @@
+
+ #define AMD_PSTATE_TRANSITION_LATENCY 20000
+ #define AMD_PSTATE_TRANSITION_DELAY 1000
+-#define AMD_PSTATE_PREFCORE_THRESHOLD 166
++#define CPPC_HIGHEST_PERF_PERFORMANCE 196
++#define CPPC_HIGHEST_PERF_DEFAULT 166
+
+ /*
+ * TODO: We need more time to fine tune processors with shared memory solution
+@@ -313,6 +314,21 @@ static inline int amd_pstate_enable(bool
+ return static_call(amd_pstate_enable)(enable);
+ }
+
++static u32 amd_pstate_highest_perf_set(struct amd_cpudata *cpudata)
++{
++ struct cpuinfo_x86 *c = &cpu_data(0);
++
++ /*
++ * For AMD CPUs with Family ID 19H and Model ID range 0x70 to 0x7f,
++ * the highest performance level is set to 196.
++ * https://bugzilla.kernel.org/show_bug.cgi?id=218759
++ */
++ if (c->x86 == 0x19 && (c->x86_model >= 0x70 && c->x86_model <= 0x7f))
++ return CPPC_HIGHEST_PERF_PERFORMANCE;
++
++ return CPPC_HIGHEST_PERF_DEFAULT;
++}
++
+ static int pstate_init_perf(struct amd_cpudata *cpudata)
+ {
+ u64 cap1;
+@@ -329,7 +345,7 @@ static int pstate_init_perf(struct amd_c
+ * the default max perf.
+ */
+ if (cpudata->hw_prefcore)
+- highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
++ highest_perf = amd_pstate_highest_perf_set(cpudata);
+ else
+ highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
+
+@@ -352,7 +368,7 @@ static int cppc_init_perf(struct amd_cpu
+ return ret;
+
+ if (cpudata->hw_prefcore)
+- highest_perf = AMD_PSTATE_PREFCORE_THRESHOLD;
++ highest_perf = amd_pstate_highest_perf_set(cpudata);
+ else
+ highest_perf = cppc_perf.highest_perf;
+