Merge branch 'fixes' into linux-next

* fixes:
  thermal/thresholds: Fix boundaries and detection routine
  thermal/thresholds: Fix uapi header macros leading to a compilation error
  cpufreq/amd-pstate: Use boost numerator for upper bound of frequencies
  cpufreq/amd-pstate: Store the boost numerator as highest perf again
  cpufreq/amd-pstate: Detect preferred core support before driver registration
This commit is contained in:
Rafael J. Wysocki 2024-12-18 15:41:26 +01:00
commit 45f6b5215e
4 changed files with 69 additions and 65 deletions

View File

@ -251,9 +251,7 @@ performance supported in `AMD CPPC Performance Capability <perf_cap_>`_).
In some ASICs, the highest CPPC performance is not the one in the ``_CPC`` 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 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 still supported, this maximum frequency will be larger than the one in
``cpuinfo``. On systems that support preferred core, the driver will have ``cpuinfo``.
different values for some cores than others and this will reflect the values
advertised by the platform at bootup.
This attribute is read-only. This attribute is read-only.
``amd_pstate_lowest_nonlinear_freq`` ``amd_pstate_lowest_nonlinear_freq``

View File

@ -374,15 +374,19 @@ static inline int amd_pstate_cppc_enable(bool enable)
static int msr_init_perf(struct amd_cpudata *cpudata) static int msr_init_perf(struct amd_cpudata *cpudata)
{ {
u64 cap1; u64 cap1, numerator;
int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1, int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
&cap1); &cap1);
if (ret) if (ret)
return ret; return ret;
WRITE_ONCE(cpudata->highest_perf, AMD_CPPC_HIGHEST_PERF(cap1)); ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator);
WRITE_ONCE(cpudata->max_limit_perf, AMD_CPPC_HIGHEST_PERF(cap1)); if (ret)
return ret;
WRITE_ONCE(cpudata->highest_perf, numerator);
WRITE_ONCE(cpudata->max_limit_perf, numerator);
WRITE_ONCE(cpudata->nominal_perf, AMD_CPPC_NOMINAL_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_nonlinear_perf, AMD_CPPC_LOWNONLIN_PERF(cap1));
WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1)); WRITE_ONCE(cpudata->lowest_perf, AMD_CPPC_LOWEST_PERF(cap1));
@ -394,13 +398,18 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
static int shmem_init_perf(struct amd_cpudata *cpudata) static int shmem_init_perf(struct amd_cpudata *cpudata)
{ {
struct cppc_perf_caps cppc_perf; struct cppc_perf_caps cppc_perf;
u64 numerator;
int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf); int ret = cppc_get_perf_caps(cpudata->cpu, &cppc_perf);
if (ret) if (ret)
return ret; return ret;
WRITE_ONCE(cpudata->highest_perf, cppc_perf.highest_perf); ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator);
WRITE_ONCE(cpudata->max_limit_perf, cppc_perf.highest_perf); if (ret)
return ret;
WRITE_ONCE(cpudata->highest_perf, numerator);
WRITE_ONCE(cpudata->max_limit_perf, numerator);
WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf); WRITE_ONCE(cpudata->nominal_perf, cppc_perf.nominal_perf);
WRITE_ONCE(cpudata->lowest_nonlinear_perf, WRITE_ONCE(cpudata->lowest_nonlinear_perf,
cppc_perf.lowest_nonlinear_perf); cppc_perf.lowest_nonlinear_perf);
@ -561,16 +570,13 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy_data)
static int amd_pstate_update_min_max_limit(struct cpufreq_policy *policy) static int amd_pstate_update_min_max_limit(struct cpufreq_policy *policy)
{ {
u32 max_limit_perf, min_limit_perf, lowest_perf, max_perf; u32 max_limit_perf, min_limit_perf, lowest_perf, max_perf, max_freq;
struct amd_cpudata *cpudata = policy->driver_data; struct amd_cpudata *cpudata = policy->driver_data;
if (cpudata->boost_supported && !policy->boost_enabled) max_perf = READ_ONCE(cpudata->highest_perf);
max_perf = READ_ONCE(cpudata->nominal_perf); max_freq = READ_ONCE(cpudata->max_freq);
else max_limit_perf = div_u64(policy->max * max_perf, max_freq);
max_perf = READ_ONCE(cpudata->highest_perf); min_limit_perf = div_u64(policy->min * max_perf, max_freq);
max_limit_perf = div_u64(policy->max * max_perf, policy->cpuinfo.max_freq);
min_limit_perf = div_u64(policy->min * max_perf, policy->cpuinfo.max_freq);
lowest_perf = READ_ONCE(cpudata->lowest_perf); lowest_perf = READ_ONCE(cpudata->lowest_perf);
if (min_limit_perf < lowest_perf) if (min_limit_perf < lowest_perf)
@ -889,7 +895,6 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
{ {
int ret; int ret;
u32 min_freq, max_freq; u32 min_freq, max_freq;
u64 numerator;
u32 nominal_perf, nominal_freq; u32 nominal_perf, nominal_freq;
u32 lowest_nonlinear_perf, lowest_nonlinear_freq; u32 lowest_nonlinear_perf, lowest_nonlinear_freq;
u32 boost_ratio, lowest_nonlinear_ratio; u32 boost_ratio, lowest_nonlinear_ratio;
@ -911,10 +916,7 @@ static int amd_pstate_init_freq(struct amd_cpudata *cpudata)
nominal_perf = READ_ONCE(cpudata->nominal_perf); nominal_perf = READ_ONCE(cpudata->nominal_perf);
ret = amd_get_boost_ratio_numerator(cpudata->cpu, &numerator); boost_ratio = div_u64(cpudata->highest_perf << SCHED_CAPACITY_SHIFT, nominal_perf);
if (ret)
return ret;
boost_ratio = div_u64(numerator << SCHED_CAPACITY_SHIFT, nominal_perf);
max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000; max_freq = (nominal_freq * boost_ratio >> SCHED_CAPACITY_SHIFT) * 1000;
lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf); lowest_nonlinear_perf = READ_ONCE(cpudata->lowest_nonlinear_perf);
@ -1869,18 +1871,18 @@ static int __init amd_pstate_init(void)
static_call_update(amd_pstate_update_perf, shmem_update_perf); static_call_update(amd_pstate_update_perf, shmem_update_perf);
} }
ret = amd_pstate_register_driver(cppc_state);
if (ret) {
pr_err("failed to register with return %d\n", ret);
return ret;
}
if (amd_pstate_prefcore) { if (amd_pstate_prefcore) {
ret = amd_detect_prefcore(&amd_pstate_prefcore); ret = amd_detect_prefcore(&amd_pstate_prefcore);
if (ret) if (ret)
return ret; return ret;
} }
ret = amd_pstate_register_driver(cppc_state);
if (ret) {
pr_err("failed to register with return %d\n", ret);
return ret;
}
dev_root = bus_get_dev_root(&cpu_subsys); dev_root = bus_get_dev_root(&cpu_subsys);
if (dev_root) { if (dev_root) {
ret = sysfs_create_group(&dev_root->kobj, &amd_pstate_global_attr_group); ret = sysfs_create_group(&dev_root->kobj, &amd_pstate_global_attr_group);

View File

@ -69,40 +69,18 @@ static struct user_threshold *__thermal_thresholds_find(const struct list_head *
return NULL; return NULL;
} }
static bool __thermal_threshold_is_crossed(struct user_threshold *threshold, int temperature,
int last_temperature, int direction,
int *low, int *high)
{
if (temperature >= threshold->temperature) {
if (threshold->temperature > *low &&
THERMAL_THRESHOLD_WAY_DOWN & threshold->direction)
*low = threshold->temperature;
if (last_temperature < threshold->temperature &&
threshold->direction & direction)
return true;
} else {
if (threshold->temperature < *high && THERMAL_THRESHOLD_WAY_UP
& threshold->direction)
*high = threshold->temperature;
if (last_temperature >= threshold->temperature &&
threshold->direction & direction)
return true;
}
return false;
}
static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int temperature, static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int temperature,
int last_temperature, int *low, int *high) int last_temperature)
{ {
struct user_threshold *t; struct user_threshold *t;
list_for_each_entry(t, thresholds, list_node) { list_for_each_entry(t, thresholds, list_node) {
if (__thermal_threshold_is_crossed(t, temperature, last_temperature,
THERMAL_THRESHOLD_WAY_UP, low, high)) if (!(t->direction & THERMAL_THRESHOLD_WAY_UP))
continue;
if (temperature >= t->temperature &&
last_temperature < t->temperature)
return true; return true;
} }
@ -110,19 +88,43 @@ static bool thermal_thresholds_handle_raising(struct list_head *thresholds, int
} }
static bool thermal_thresholds_handle_dropping(struct list_head *thresholds, int temperature, static bool thermal_thresholds_handle_dropping(struct list_head *thresholds, int temperature,
int last_temperature, int *low, int *high) int last_temperature)
{ {
struct user_threshold *t; struct user_threshold *t;
list_for_each_entry_reverse(t, thresholds, list_node) { list_for_each_entry_reverse(t, thresholds, list_node) {
if (__thermal_threshold_is_crossed(t, temperature, last_temperature,
THERMAL_THRESHOLD_WAY_DOWN, low, high)) if (!(t->direction & THERMAL_THRESHOLD_WAY_DOWN))
continue;
if (temperature <= t->temperature &&
last_temperature > t->temperature)
return true; return true;
} }
return false; return false;
} }
static void thermal_threshold_find_boundaries(struct list_head *thresholds, int temperature,
int *low, int *high)
{
struct user_threshold *t;
list_for_each_entry(t, thresholds, list_node) {
if (temperature < t->temperature &&
(t->direction & THERMAL_THRESHOLD_WAY_UP) &&
*high > t->temperature)
*high = t->temperature;
}
list_for_each_entry_reverse(t, thresholds, list_node) {
if (temperature > t->temperature &&
(t->direction & THERMAL_THRESHOLD_WAY_DOWN) &&
*low < t->temperature)
*low = t->temperature;
}
}
void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high) void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *high)
{ {
struct list_head *thresholds = &tz->user_thresholds; struct list_head *thresholds = &tz->user_thresholds;
@ -132,6 +134,8 @@ void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *hi
lockdep_assert_held(&tz->lock); lockdep_assert_held(&tz->lock);
thermal_threshold_find_boundaries(thresholds, temperature, low, high);
/* /*
* We need a second update in order to detect a threshold being crossed * We need a second update in order to detect a threshold being crossed
*/ */
@ -151,12 +155,12 @@ void thermal_thresholds_handle(struct thermal_zone_device *tz, int *low, int *hi
* - decreased : thresholds are crossed the way down * - decreased : thresholds are crossed the way down
*/ */
if (temperature > last_temperature) { if (temperature > last_temperature) {
if (thermal_thresholds_handle_raising(thresholds, temperature, if (thermal_thresholds_handle_raising(thresholds,
last_temperature, low, high)) temperature, last_temperature))
thermal_notify_threshold_up(tz); thermal_notify_threshold_up(tz);
} else { } else {
if (thermal_thresholds_handle_dropping(thresholds, temperature, if (thermal_thresholds_handle_dropping(thresholds,
last_temperature, low, high)) temperature, last_temperature))
thermal_notify_threshold_down(tz); thermal_notify_threshold_down(tz);
} }
} }

View File

@ -3,8 +3,8 @@
#define _UAPI_LINUX_THERMAL_H #define _UAPI_LINUX_THERMAL_H
#define THERMAL_NAME_LENGTH 20 #define THERMAL_NAME_LENGTH 20
#define THERMAL_THRESHOLD_WAY_UP BIT(0) #define THERMAL_THRESHOLD_WAY_UP 0x1
#define THERMAL_THRESHOLD_WAY_DOWN BIT(1) #define THERMAL_THRESHOLD_WAY_DOWN 0x2
enum thermal_device_mode { enum thermal_device_mode {
THERMAL_DEVICE_DISABLED = 0, THERMAL_DEVICE_DISABLED = 0,