mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-24 04:34:08 +08:00
second round of amd-pstate changes for 6.12 (second try):
* Move the calculation of the AMD boost numerator outside of amd-pstate, correcting acpi-cpufreq on systems with preferred cores * Harden preferred core detection to avoid potential false positives * Add extra unit test coverage for mode state machine -----BEGIN PGP SIGNATURE----- iQJOBAABCgA4FiEECwtuSU6dXvs5GA2aLRkspiR3AnYFAmbhviEaHG1hcmlvLmxp bW9uY2llbGxvQGFtZC5jb20ACgkQLRkspiR3AnYqDA//TrvmXcpk1mnVJw3Y7MG0 /n8dsLpxqVtEf+USnlGR+iRhgSQ/W/Kr7b5a+jmdCwpHChuWHt2FnNgcHLIxDnZC vmEJ02/2BCRoPKvcvV4VTh0ATu3O9nqwQiBVWBdNjDy+Dzr0pzA+SQopt1hCIsO2 mzUodhpiBqYKlMf/i6+aM1gZCGGqoRC40aGqnJsgegb61vl7zIc2ZcbTxUQlyTfv t6J73IXLx8+YtrjejBYc7mRHhMQ2hCKy92C/8cNoGocj5faSKsAA3OUDcWq8qX0U zK3GGGdW8MLHSbt3VyntstnfiLL7TnzowcjvrMudIWpjC1987GlE9BApbN9VRZ8e ARN3Y7/ltjut/1fRB97BwjI9aDpzA0122Qzy4UOcK8o+be1eIr+ihV3Z9EN/snWg 0L/oq5+rGHvvIzf1BwGhoPSvgBIu7eMIYDcRxKPlEiKsbXrL4DdJC/nXgaZ/HiGO eHx1dNy7LFrdnEwVI1frZWC6ZuZcpmOBdhnfU+leVxzB3Z++Qc266rsxKBsc5taZ PPV18pxfbbl3iL85KDIbuBUCmA0aY8WEdCKtfXpl7zlB5g0fZQLyYeUbvahK08Sk vyQAnPECbX/4v1Vx54Z70GPk0XD2+TXdg8yApnXrmRc36z/SLdprk5hPKbKhZu/r iPxFUnvd0HCtjsLrsq/qUiQ= =R4HZ -----END PGP SIGNATURE----- Merge tag 'amd-pstate-v6.12-2024-09-11' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux Merge the second round of amd-pstate changes for 6.12 from Mario Limonciello: "* Move the calculation of the AMD boost numerator outside of amd-pstate, correcting acpi-cpufreq on systems with preferred cores * Harden preferred core detection to avoid potential false positives * Add extra unit test coverage for mode state machine" * tag 'amd-pstate-v6.12-2024-09-11' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux: cpufreq/amd-pstate-ut: Fix an "Uninitialized variables" issue cpufreq/amd-pstate-ut: Add test case for mode switches cpufreq/amd-pstate: Export symbols for changing modes amd-pstate: Add missing documentation for `amd_pstate_prefcore_ranking` cpufreq: amd-pstate: Add documentation for `amd_pstate_hw_prefcore` cpufreq: amd-pstate: Optimize amd_pstate_update_limits() cpufreq: amd-pstate: Merge amd_pstate_highest_perf_set() into amd_get_boost_ratio_numerator() x86/amd: Detect preferred cores in amd_get_boost_ratio_numerator() x86/amd: Move amd_get_highest_perf() out of amd-pstate ACPI: CPPC: Adjust debug messages in amd_set_max_freq_ratio() to warn ACPI: CPPC: Drop check for non zero perf ratio x86/amd: Rename amd_get_highest_perf() to amd_get_boost_ratio_numerator() ACPI: CPPC: Adjust return code for inline functions in !CONFIG_ACPI_CPPC_LIB x86/amd: Move amd_get_highest_perf() from amd.c to cppc.c
This commit is contained in:
commit
9bcf30348f
@ -251,7 +251,9 @@ performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
|
||||
In some ASICs, the highest CPPC performance is not the one in the ``_CPC``
|
||||
table, so we need to expose it to sysfs. If boost is not active, but
|
||||
still supported, this maximum frequency will be larger than the one in
|
||||
``cpuinfo``.
|
||||
``cpuinfo``. On systems that support preferred core, the driver will have
|
||||
different values for some cores than others and this will reflect the values
|
||||
advertised by the platform at bootup.
|
||||
This attribute is read-only.
|
||||
|
||||
``amd_pstate_lowest_nonlinear_freq``
|
||||
@ -262,6 +264,17 @@ lowest non-linear performance in `AMD CPPC Performance Capability
|
||||
<perf_cap_>`_.)
|
||||
This attribute is read-only.
|
||||
|
||||
``amd_pstate_hw_prefcore``
|
||||
|
||||
Whether the platform supports the preferred core feature and it has been
|
||||
enabled. This attribute is read-only.
|
||||
|
||||
``amd_pstate_prefcore_ranking``
|
||||
|
||||
The performance ranking of the core. This number doesn't have any unit, but
|
||||
larger numbers are preferred at the time of reading. This can change at
|
||||
runtime based on platform conditions. This attribute is read-only.
|
||||
|
||||
``energy_performance_available_preferences``
|
||||
|
||||
A list of all the supported EPP preferences that could be used for
|
||||
|
@ -691,8 +691,6 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
|
||||
}
|
||||
|
||||
#ifdef CONFIG_CPU_SUP_AMD
|
||||
extern u32 amd_get_highest_perf(void);
|
||||
|
||||
/*
|
||||
* Issue a DIV 0/1 insn to clear any division data from previous DIV
|
||||
* operations.
|
||||
@ -705,7 +703,6 @@ static __always_inline void amd_clear_divider(void)
|
||||
|
||||
extern void amd_check_microcode(void);
|
||||
#else
|
||||
static inline u32 amd_get_highest_perf(void) { return 0; }
|
||||
static inline void amd_clear_divider(void) { }
|
||||
static inline void amd_check_microcode(void) { }
|
||||
#endif
|
||||
|
@ -9,6 +9,17 @@
|
||||
#include <asm/processor.h>
|
||||
#include <asm/topology.h>
|
||||
|
||||
#define CPPC_HIGHEST_PERF_PERFORMANCE 196
|
||||
#define CPPC_HIGHEST_PERF_PREFCORE 166
|
||||
|
||||
enum amd_pref_core {
|
||||
AMD_PREF_CORE_UNKNOWN = 0,
|
||||
AMD_PREF_CORE_SUPPORTED,
|
||||
AMD_PREF_CORE_UNSUPPORTED,
|
||||
};
|
||||
static enum amd_pref_core amd_pref_core_detected;
|
||||
static u64 boost_numerator;
|
||||
|
||||
/* Refer to drivers/acpi/cppc_acpi.c for the description of functions */
|
||||
|
||||
bool cpc_supported_by_cpu(void)
|
||||
@ -69,31 +80,30 @@ int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
|
||||
static void amd_set_max_freq_ratio(void)
|
||||
{
|
||||
struct cppc_perf_caps perf_caps;
|
||||
u64 highest_perf, nominal_perf;
|
||||
u64 numerator, nominal_perf;
|
||||
u64 perf_ratio;
|
||||
int rc;
|
||||
|
||||
rc = cppc_get_perf_caps(0, &perf_caps);
|
||||
if (rc) {
|
||||
pr_debug("Could not retrieve perf counters (%d)\n", rc);
|
||||
pr_warn("Could not retrieve perf counters (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
|
||||
highest_perf = amd_get_highest_perf();
|
||||
rc = amd_get_boost_ratio_numerator(0, &numerator);
|
||||
if (rc) {
|
||||
pr_warn("Could not retrieve highest performance (%d)\n", rc);
|
||||
return;
|
||||
}
|
||||
nominal_perf = perf_caps.nominal_perf;
|
||||
|
||||
if (!highest_perf || !nominal_perf) {
|
||||
pr_debug("Could not retrieve highest or nominal performance\n");
|
||||
if (!nominal_perf) {
|
||||
pr_warn("Could not retrieve nominal performance\n");
|
||||
return;
|
||||
}
|
||||
|
||||
perf_ratio = div_u64(highest_perf * SCHED_CAPACITY_SCALE, nominal_perf);
|
||||
/* midpoint between max_boost and max_P */
|
||||
perf_ratio = (perf_ratio + SCHED_CAPACITY_SCALE) >> 1;
|
||||
if (!perf_ratio) {
|
||||
pr_debug("Non-zero highest/nominal perf values led to a 0 ratio\n");
|
||||
return;
|
||||
}
|
||||
perf_ratio = (div_u64(numerator * SCHED_CAPACITY_SCALE, nominal_perf) + SCHED_CAPACITY_SCALE) >> 1;
|
||||
|
||||
freq_invariance_set_perf_ratio(perf_ratio, false);
|
||||
}
|
||||
@ -116,3 +126,143 @@ void init_freq_invariance_cppc(void)
|
||||
init_done = true;
|
||||
mutex_unlock(&freq_invariance_lock);
|
||||
}
|
||||
|
||||
/*
|
||||
* Get the highest performance register value.
|
||||
* @cpu: CPU from which to get highest performance.
|
||||
* @highest_perf: Return address for highest performance value.
|
||||
*
|
||||
* Return: 0 for success, negative error code otherwise.
|
||||
*/
|
||||
int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
|
||||
{
|
||||
u64 val;
|
||||
int ret;
|
||||
|
||||
if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
|
||||
ret = rdmsrl_safe_on_cpu(cpu, MSR_AMD_CPPC_CAP1, &val);
|
||||
if (ret)
|
||||
goto out;
|
||||
|
||||
val = AMD_CPPC_HIGHEST_PERF(val);
|
||||
} else {
|
||||
ret = cppc_get_highest_perf(cpu, &val);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
|
||||
WRITE_ONCE(*highest_perf, (u32)val);
|
||||
out:
|
||||
return ret;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_get_highest_perf);
|
||||
|
||||
/**
|
||||
* amd_detect_prefcore: Detect if CPUs in the system support preferred cores
|
||||
* @detected: Output variable for the result of the detection.
|
||||
*
|
||||
* Determine whether CPUs in the system support preferred cores. On systems
|
||||
* that support preferred cores, different highest perf values will be found
|
||||
* on different cores. On other systems, the highest perf value will be the
|
||||
* same on all cores.
|
||||
*
|
||||
* The result of the detection will be stored in the 'detected' parameter.
|
||||
*
|
||||
* Return: 0 for success, negative error code otherwise
|
||||
*/
|
||||
int amd_detect_prefcore(bool *detected)
|
||||
{
|
||||
int cpu, count = 0;
|
||||
u64 highest_perf[2] = {0};
|
||||
|
||||
if (WARN_ON(!detected))
|
||||
return -EINVAL;
|
||||
|
||||
switch (amd_pref_core_detected) {
|
||||
case AMD_PREF_CORE_SUPPORTED:
|
||||
*detected = true;
|
||||
return 0;
|
||||
case AMD_PREF_CORE_UNSUPPORTED:
|
||||
*detected = false;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
for_each_present_cpu(cpu) {
|
||||
u32 tmp;
|
||||
int ret;
|
||||
|
||||
ret = amd_get_highest_perf(cpu, &tmp);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (!count || (count == 1 && tmp != highest_perf[0]))
|
||||
highest_perf[count++] = tmp;
|
||||
|
||||
if (count == 2)
|
||||
break;
|
||||
}
|
||||
|
||||
*detected = (count == 2);
|
||||
boost_numerator = highest_perf[0];
|
||||
|
||||
amd_pref_core_detected = *detected ? AMD_PREF_CORE_SUPPORTED :
|
||||
AMD_PREF_CORE_UNSUPPORTED;
|
||||
|
||||
pr_debug("AMD CPPC preferred core is %ssupported (highest perf: 0x%llx)\n",
|
||||
*detected ? "" : "un", highest_perf[0]);
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_detect_prefcore);
|
||||
|
||||
/**
|
||||
* amd_get_boost_ratio_numerator: Get the numerator to use for boost ratio calculation
|
||||
* @cpu: CPU to get numerator for.
|
||||
* @numerator: Output variable for numerator.
|
||||
*
|
||||
* Determine the numerator to use for calculating the boost ratio on
|
||||
* a CPU. On systems that support preferred cores, this will be a hardcoded
|
||||
* value. On other systems this will the highest performance register value.
|
||||
*
|
||||
* If booting the system with amd-pstate enabled but preferred cores disabled then
|
||||
* the correct boost numerator will be returned to match hardware capabilities
|
||||
* even if the preferred cores scheduling hints are not enabled.
|
||||
*
|
||||
* Return: 0 for success, negative error code otherwise.
|
||||
*/
|
||||
int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
|
||||
{
|
||||
bool prefcore;
|
||||
int ret;
|
||||
|
||||
ret = amd_detect_prefcore(&prefcore);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* without preferred cores, return the highest perf register value */
|
||||
if (!prefcore) {
|
||||
*numerator = boost_numerator;
|
||||
return 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 (cpu_feature_enabled(X86_FEATURE_ZEN4)) {
|
||||
switch (boot_cpu_data.x86_model) {
|
||||
case 0x70 ... 0x7f:
|
||||
*numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
|
||||
return 0;
|
||||
default:
|
||||
break;
|
||||
}
|
||||
}
|
||||
*numerator = CPPC_HIGHEST_PERF_PREFCORE;
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_get_boost_ratio_numerator);
|
||||
|
@ -1190,22 +1190,6 @@ unsigned long amd_get_dr_addr_mask(unsigned int dr)
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_get_dr_addr_mask);
|
||||
|
||||
u32 amd_get_highest_perf(void)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &boot_cpu_data;
|
||||
|
||||
if (c->x86 == 0x17 && ((c->x86_model >= 0x30 && c->x86_model < 0x40) ||
|
||||
(c->x86_model >= 0x70 && c->x86_model < 0x80)))
|
||||
return 166;
|
||||
|
||||
if (c->x86 == 0x19 && ((c->x86_model >= 0x20 && c->x86_model < 0x30) ||
|
||||
(c->x86_model >= 0x40 && c->x86_model < 0x70)))
|
||||
return 166;
|
||||
|
||||
return 255;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_get_highest_perf);
|
||||
|
||||
static void zenbleed_check_cpu(void *unused)
|
||||
{
|
||||
struct cpuinfo_x86 *c = &cpu_data(smp_processor_id());
|
||||
|
@ -642,10 +642,16 @@ static u64 get_max_boost_ratio(unsigned int cpu)
|
||||
return 0;
|
||||
}
|
||||
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
|
||||
highest_perf = amd_get_highest_perf();
|
||||
else
|
||||
if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
|
||||
ret = amd_get_boost_ratio_numerator(cpu, &highest_perf);
|
||||
if (ret) {
|
||||
pr_debug("CPU%d: Unable to get boost ratio numerator (%d)\n",
|
||||
cpu, ret);
|
||||
return 0;
|
||||
}
|
||||
} else {
|
||||
highest_perf = perf_caps.highest_perf;
|
||||
}
|
||||
|
||||
nominal_perf = perf_caps.nominal_perf;
|
||||
|
||||
|
@ -54,12 +54,14 @@ static void amd_pstate_ut_acpi_cpc_valid(u32 index);
|
||||
static void amd_pstate_ut_check_enabled(u32 index);
|
||||
static void amd_pstate_ut_check_perf(u32 index);
|
||||
static void amd_pstate_ut_check_freq(u32 index);
|
||||
static void amd_pstate_ut_check_driver(u32 index);
|
||||
|
||||
static struct amd_pstate_ut_struct amd_pstate_ut_cases[] = {
|
||||
{"amd_pstate_ut_acpi_cpc_valid", amd_pstate_ut_acpi_cpc_valid },
|
||||
{"amd_pstate_ut_check_enabled", amd_pstate_ut_check_enabled },
|
||||
{"amd_pstate_ut_check_perf", amd_pstate_ut_check_perf },
|
||||
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq }
|
||||
{"amd_pstate_ut_check_freq", amd_pstate_ut_check_freq },
|
||||
{"amd_pstate_ut_check_driver", amd_pstate_ut_check_driver }
|
||||
};
|
||||
|
||||
static bool get_shared_mem(void)
|
||||
@ -257,6 +259,43 @@ skip_test:
|
||||
cpufreq_cpu_put(policy);
|
||||
}
|
||||
|
||||
static int amd_pstate_set_mode(enum amd_pstate_mode mode)
|
||||
{
|
||||
const char *mode_str = amd_pstate_get_mode_string(mode);
|
||||
|
||||
pr_debug("->setting mode to %s\n", mode_str);
|
||||
|
||||
return amd_pstate_update_status(mode_str, strlen(mode_str));
|
||||
}
|
||||
|
||||
static void amd_pstate_ut_check_driver(u32 index)
|
||||
{
|
||||
enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
|
||||
int ret;
|
||||
|
||||
for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
|
||||
ret = amd_pstate_set_mode(mode1);
|
||||
if (ret)
|
||||
goto out;
|
||||
for (mode2 = AMD_PSTATE_DISABLE; mode2 < AMD_PSTATE_MAX; mode2++) {
|
||||
if (mode1 == mode2)
|
||||
continue;
|
||||
ret = amd_pstate_set_mode(mode2);
|
||||
if (ret)
|
||||
goto out;
|
||||
}
|
||||
}
|
||||
out:
|
||||
if (ret)
|
||||
pr_warn("%s: failed to update status for %s->%s: %d\n", __func__,
|
||||
amd_pstate_get_mode_string(mode1),
|
||||
amd_pstate_get_mode_string(mode2), ret);
|
||||
|
||||
amd_pstate_ut_cases[index].result = ret ?
|
||||
AMD_PSTATE_UT_RESULT_FAIL :
|
||||
AMD_PSTATE_UT_RESULT_PASS;
|
||||
}
|
||||
|
||||
static int __init amd_pstate_ut_init(void)
|
||||
{
|
||||
u32 i = 0, arr_size = ARRAY_SIZE(amd_pstate_ut_cases);
|
||||
|
@ -52,26 +52,12 @@
|
||||
#define AMD_PSTATE_TRANSITION_LATENCY 20000
|
||||
#define AMD_PSTATE_TRANSITION_DELAY 1000
|
||||
#define AMD_PSTATE_FAST_CPPC_TRANSITION_DELAY 600
|
||||
#define CPPC_HIGHEST_PERF_PERFORMANCE 196
|
||||
#define CPPC_HIGHEST_PERF_DEFAULT 166
|
||||
|
||||
#define AMD_CPPC_EPP_PERFORMANCE 0x00
|
||||
#define AMD_CPPC_EPP_BALANCE_PERFORMANCE 0x80
|
||||
#define AMD_CPPC_EPP_BALANCE_POWERSAVE 0xBF
|
||||
#define AMD_CPPC_EPP_POWERSAVE 0xFF
|
||||
|
||||
/*
|
||||
* enum amd_pstate_mode - driver working mode of amd pstate
|
||||
*/
|
||||
enum amd_pstate_mode {
|
||||
AMD_PSTATE_UNDEFINED = 0,
|
||||
AMD_PSTATE_DISABLE,
|
||||
AMD_PSTATE_PASSIVE,
|
||||
AMD_PSTATE_ACTIVE,
|
||||
AMD_PSTATE_GUIDED,
|
||||
AMD_PSTATE_MAX,
|
||||
};
|
||||
|
||||
static const char * const amd_pstate_mode_string[] = {
|
||||
[AMD_PSTATE_UNDEFINED] = "undefined",
|
||||
[AMD_PSTATE_DISABLE] = "disable",
|
||||
@ -81,6 +67,14 @@ static const char * const amd_pstate_mode_string[] = {
|
||||
NULL,
|
||||
};
|
||||
|
||||
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode)
|
||||
{
|
||||
if (mode < 0 || mode >= AMD_PSTATE_MAX)
|
||||
return NULL;
|
||||
return amd_pstate_mode_string[mode];
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_pstate_get_mode_string);
|
||||
|
||||
struct quirk_entry {
|
||||
u32 nominal_freq;
|
||||
u32 lowest_freq;
|
||||
@ -372,43 +366,17 @@ static inline int amd_pstate_enable(bool enable)
|
||||
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;
|
||||
u32 highest_perf;
|
||||
|
||||
int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
|
||||
&cap1);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
/* 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.
|
||||
*/
|
||||
if (cpudata->hw_prefcore)
|
||||
highest_perf = amd_pstate_highest_perf_set(cpudata);
|
||||
else
|
||||
highest_perf = AMD_CPPC_HIGHEST_PERF(cap1);
|
||||
|
||||
WRITE_ONCE(cpudata->highest_perf, highest_perf);
|
||||
WRITE_ONCE(cpudata->max_limit_perf, highest_perf);
|
||||
WRITE_ONCE(cpudata->highest_perf, AMD_CPPC_HIGHEST_PERF(cap1));
|
||||
WRITE_ONCE(cpudata->max_limit_perf, AMD_CPPC_HIGHEST_PERF(cap1));
|
||||
WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_PERF(cap1));
|
||||
WRITE_ONCE(cpudata->lowest_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
|
||||
WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1));
|
||||
@ -420,19 +388,13 @@ static int pstate_init_perf(struct amd_cpudata *cpudata)
|
||||
static int cppc_init_perf(struct amd_cpudata *cpudata)
|
||||
{
|
||||
struct cppc_perf_caps cppc_perf;
|
||||
u32 highest_perf;
|
||||
|
||||
int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
|
||||
if (ret)
|
||||
return ret;
|
||||
|
||||
if (cpudata->hw_prefcore)
|
||||
highest_perf = amd_pstate_highest_perf_set(cpudata);
|
||||
else
|
||||
highest_perf = cppc_perf.highest_perf;
|
||||
|
||||
WRITE_ONCE(cpudata->highest_perf, highest_perf);
|
||||
WRITE_ONCE(cpudata->max_limit_perf, highest_perf);
|
||||
WRITE_ONCE(cpudata->highest_perf, cppc_perf.highest_perf);
|
||||
WRITE_ONCE(cpudata->max_limit_perf, cppc_perf.highest_perf);
|
||||
WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
|
||||
WRITE_ONCE(cpudata->lowest_nonlinear_perf,
|
||||
cppc_perf.lowest_nonlinear_perf);
|
||||
@ -811,66 +773,22 @@ static void amd_pstste_sched_prefcore_workfn(struct work_struct *work)
|
||||
}
|
||||
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 (cpu_feature_enabled(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)
|
||||
/* user disabled or not detected */
|
||||
if (!amd_pstate_prefcore)
|
||||
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);
|
||||
sched_set_itmt_core_prio((int)READ_ONCE(cpudata->highest_perf), cpudata->cpu);
|
||||
|
||||
schedule_work(&sched_prefcore_work);
|
||||
}
|
||||
@ -888,17 +806,17 @@ static void amd_pstate_update_limits(unsigned int cpu)
|
||||
|
||||
cpudata = policy->driver_data;
|
||||
|
||||
mutex_lock(&amd_pstate_driver_lock);
|
||||
if ((!amd_pstate_prefcore) || (!cpudata->hw_prefcore))
|
||||
goto free_cpufreq_put;
|
||||
if (!amd_pstate_prefcore)
|
||||
return;
|
||||
|
||||
ret = amd_pstate_get_highest_perf(cpu, &cur_high);
|
||||
mutex_lock(&amd_pstate_driver_lock);
|
||||
ret = amd_get_highest_perf(cpu, &cur_high);
|
||||
if (ret)
|
||||
goto free_cpufreq_put;
|
||||
|
||||
prev_high = READ_ONCE(cpudata->prefcore_ranking);
|
||||
if (prev_high != cur_high) {
|
||||
highest_perf_changed = true;
|
||||
highest_perf_changed = (prev_high != cur_high);
|
||||
if (highest_perf_changed) {
|
||||
WRITE_ONCE(cpudata->prefcore_ranking, cur_high);
|
||||
|
||||
if (cur_high < CPPC_MAX_PERF)
|
||||
@ -962,8 +880,8 @@ static u32 amd_pstate_get_transition_latency(unsigned int cpu)
|
||||
static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
||||
{
|
||||
int ret;
|
||||
u32 min_freq;
|
||||
u32 highest_perf, max_freq;
|
||||
u32 min_freq, max_freq;
|
||||
u64 numerator;
|
||||
u32 nominal_perf, nominal_freq;
|
||||
u32 lowest_nonlinear_perf, lowest_nonlinear_freq;
|
||||
u32 boost_ratio, lowest_nonlinear_ratio;
|
||||
@ -985,8 +903,10 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
|
||||
|
||||
nominal_perf = READ_ONCE(cpudata->nominal_perf);
|
||||
|
||||
highest_perf = READ_ONCE(cpudata->highest_perf);
|
||||
boost_ratio = div_u64(highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
|
||||
ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator);
|
||||
if (ret)
|
||||
return ret;
|
||||
boost_ratio = div_u64(numerator << SCHED_CAPACITY_SHIFT, nominal_perf);
|
||||
max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000;
|
||||
|
||||
lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
|
||||
@ -1041,12 +961,12 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
|
||||
|
||||
cpudata->cpu = policy->cpu;
|
||||
|
||||
amd_pstate_init_prefcore(cpudata);
|
||||
|
||||
ret = amd_pstate_init_perf(cpudata);
|
||||
if (ret)
|
||||
goto free_cpudata1;
|
||||
|
||||
amd_pstate_init_prefcore(cpudata);
|
||||
|
||||
ret = amd_pstate_init_freq(cpudata);
|
||||
if (ret)
|
||||
goto free_cpudata1;
|
||||
@ -1362,7 +1282,7 @@ static ssize_t amd_pstate_show_status(char *buf)
|
||||
return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
|
||||
}
|
||||
|
||||
static int amd_pstate_update_status(const char *buf, size_t size)
|
||||
int amd_pstate_update_status(const char *buf, size_t size)
|
||||
{
|
||||
int mode_idx;
|
||||
|
||||
@ -1379,6 +1299,7 @@ static int amd_pstate_update_status(const char *buf, size_t size)
|
||||
|
||||
return 0;
|
||||
}
|
||||
EXPORT_SYMBOL_GPL(amd_pstate_update_status);
|
||||
|
||||
static ssize_t status_show(struct device *dev,
|
||||
struct device_attribute *attr, char *buf)
|
||||
@ -1496,12 +1417,12 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
|
||||
cpudata->cpu = policy->cpu;
|
||||
cpudata->epp_policy = 0;
|
||||
|
||||
amd_pstate_init_prefcore(cpudata);
|
||||
|
||||
ret = amd_pstate_init_perf(cpudata);
|
||||
if (ret)
|
||||
goto free_cpudata1;
|
||||
|
||||
amd_pstate_init_prefcore(cpudata);
|
||||
|
||||
ret = amd_pstate_init_freq(cpudata);
|
||||
if (ret)
|
||||
goto free_cpudata1;
|
||||
@ -1963,6 +1884,12 @@ static int __init amd_pstate_init(void)
|
||||
static_call_update(amd_pstate_update_perf, cppc_update_perf);
|
||||
}
|
||||
|
||||
if (amd_pstate_prefcore) {
|
||||
ret = amd_detect_prefcore(&amd_pstate_prefcore);
|
||||
if (ret)
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* enable amd pstate feature */
|
||||
ret = amd_pstate_enable(true);
|
||||
if (ret) {
|
||||
|
@ -103,4 +103,18 @@ struct amd_cpudata {
|
||||
bool boost_state;
|
||||
};
|
||||
|
||||
/*
|
||||
* enum amd_pstate_mode - driver working mode of amd pstate
|
||||
*/
|
||||
enum amd_pstate_mode {
|
||||
AMD_PSTATE_UNDEFINED = 0,
|
||||
AMD_PSTATE_DISABLE,
|
||||
AMD_PSTATE_PASSIVE,
|
||||
AMD_PSTATE_ACTIVE,
|
||||
AMD_PSTATE_GUIDED,
|
||||
AMD_PSTATE_MAX,
|
||||
};
|
||||
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
|
||||
int amd_pstate_update_status(const char *buf, size_t size);
|
||||
|
||||
#endif /* _LINUX_AMD_PSTATE_H */
|
||||
|
@ -159,34 +159,37 @@ extern int cppc_get_epp_perf(int cpunum, u64 *epp_perf);
|
||||
extern int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable);
|
||||
extern int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps);
|
||||
extern int cppc_set_auto_sel(int cpu, bool enable);
|
||||
extern int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf);
|
||||
extern int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator);
|
||||
extern int amd_detect_prefcore(bool *detected);
|
||||
#else /* !CONFIG_ACPI_CPPC_LIB */
|
||||
static inline int cppc_get_desired_perf(int cpunum, u64 *desired_perf)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_nominal_perf(int cpunum, u64 *nominal_perf)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_highest_perf(int cpunum, u64 *highest_perf)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_perf_ctrs(int cpu, struct cppc_perf_fb_ctrs *perf_fb_ctrs)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_set_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_set_enable(int cpu, bool enable)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_perf_caps(int cpu, struct cppc_perf_caps *caps)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline bool cppc_perf_ctrs_in_pcc(void)
|
||||
{
|
||||
@ -210,27 +213,39 @@ static inline bool cpc_ffh_supported(void)
|
||||
}
|
||||
static inline int cpc_read_ffh(int cpunum, struct cpc_reg *reg, u64 *val)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cpc_write_ffh(int cpunum, struct cpc_reg *reg, u64 val)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_set_epp_perf(int cpu, struct cppc_perf_ctrls *perf_ctrls, bool enable)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_epp_perf(int cpunum, u64 *epp_perf)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_set_auto_sel(int cpu, bool enable)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int cppc_get_auto_sel_caps(int cpunum, struct cppc_perf_caps *perf_caps)
|
||||
{
|
||||
return -ENOTSUPP;
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int amd_get_highest_perf(unsigned int cpu, u32 *highest_perf)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
static inline int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
|
||||
{
|
||||
return -EOPNOTSUPP;
|
||||
}
|
||||
static inline int amd_detect_prefcore(bool *detected)
|
||||
{
|
||||
return -ENODEV;
|
||||
}
|
||||
#endif /* !CONFIG_ACPI_CPPC_LIB */
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user