Commit 41abd479 authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge tag 'amd-pstate-v6.16-2025-05-08' of...

Merge tag 'amd-pstate-v6.16-2025-05-08' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux

Merge amd-pstate content for 6.16 (5/8/25) from Mario Limonciello:

 - Add support for a new feature on some BIOS that allows setting
   "lowest CPU minimum frequency".

 - Fix the amd-pstate-ut unit tests to restore system settings when
   done.

* tag 'amd-pstate-v6.16-2025-05-08' of ssh://gitolite.kernel.org/pub/scm/linux/kernel/git/superm1/linux:
  amd-pstate-ut: Reset amd-pstate driver mode after running selftests
  cpufreq/amd-pstate: Add support for the "Requested CPU Min frequency" BIOS option
  cpufreq/amd-pstate: Add offline, online and suspend callbacks for amd_pstate_driver
  cpufreq/amd-pstate: Move max_perf limiting in amd_pstate_update
parents f1a50492 d26d1643
Loading
Loading
Loading
Loading
+12 −7
Original line number Diff line number Diff line
@@ -242,6 +242,8 @@ static int amd_pstate_set_mode(enum amd_pstate_mode mode)
static int amd_pstate_ut_check_driver(u32 index)
{
	enum amd_pstate_mode mode1, mode2 = AMD_PSTATE_DISABLE;
	enum amd_pstate_mode orig_mode = amd_pstate_get_status();
	int ret;

	for (mode1 = AMD_PSTATE_DISABLE; mode1 < AMD_PSTATE_MAX; mode1++) {
		int ret = amd_pstate_set_mode(mode1);
@@ -251,16 +253,19 @@ static int amd_pstate_ut_check_driver(u32 index)
			if (mode1 == mode2)
				continue;
			ret = amd_pstate_set_mode(mode2);
			if (ret) {
				pr_err("%s: failed to update status for %s->%s\n", __func__,
					amd_pstate_get_mode_string(mode1),
					amd_pstate_get_mode_string(mode2));
				return ret;
			}
			if (ret)
				goto out;
		}
	}

	return 0;
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_set_mode(orig_mode);
	return ret;
}

static int __init amd_pstate_ut_init(void)
+88 −25
Original line number Diff line number Diff line
@@ -389,7 +389,8 @@ static inline int amd_pstate_cppc_enable(struct cpufreq_policy *policy)
static int msr_init_perf(struct amd_cpudata *cpudata)
{
	union perf_cached perf = READ_ONCE(cpudata->perf);
	u64 cap1, numerator;
	u64 cap1, numerator, cppc_req;
	u8 min_perf;

	int ret = rdmsrl_safe_on_cpu(cpudata->cpu, MSR_AMD_CPPC_CAP1,
				     &cap1);
@@ -400,6 +401,22 @@ static int msr_init_perf(struct amd_cpudata *cpudata)
	if (ret)
		return ret;

	ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &cppc_req);
	if (ret)
		return ret;

	WRITE_ONCE(cpudata->cppc_req_cached, cppc_req);
	min_perf = FIELD_GET(AMD_CPPC_MIN_PERF_MASK, cppc_req);

	/*
	 * Clear out the min_perf part to check if the rest of the MSR is 0, if yes, this is an
	 * indication that the min_perf value is the one specified through the BIOS option
	 */
	cppc_req &= ~(AMD_CPPC_MIN_PERF_MASK);

	if (!cppc_req)
		perf.bios_min_perf = min_perf;

	perf.highest_perf = numerator;
	perf.max_limit_perf = numerator;
	perf.min_limit_perf = FIELD_GET(AMD_CPPC_LOWEST_PERF_MASK, cap1);
@@ -554,6 +571,10 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u8 min_perf,
	if (!policy)
		return;

	/* limit the max perf when core performance boost feature is disabled */
	if (!cpudata->boost_supported)
		max_perf = min_t(u8, perf.nominal_perf, max_perf);

	des_perf = clamp_t(u8, des_perf, min_perf, max_perf);

	policy->cur = perf_to_freq(perf, cpudata->nominal_freq, des_perf);
@@ -563,10 +584,6 @@ static void amd_pstate_update(struct amd_cpudata *cpudata, u8 min_perf,
		des_perf = 0;
	}

	/* limit the max perf when core performance boost feature is disabled */
	if (!cpudata->boost_supported)
		max_perf = min_t(u8, perf.nominal_perf, max_perf);

	if (trace_amd_pstate_perf_enabled() && amd_pstate_sample(cpudata)) {
		trace_amd_pstate_perf(min_perf, des_perf, max_perf, cpudata->freq,
			cpudata->cur.mperf, cpudata->cur.aperf, cpudata->cur.tsc,
@@ -580,19 +597,25 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy_data)
{
	/*
	 * Initialize lower frequency limit (i.e.policy->min) with
	 * lowest_nonlinear_frequency which is the most energy efficient
	 * frequency. Override the initial value set by cpufreq core and
	 * amd-pstate qos_requests.
	 * lowest_nonlinear_frequency or the min frequency (if) specified in BIOS,
	 * Override the initial value set by cpufreq core and amd-pstate qos_requests.
	 */
	if (policy_data->min == FREQ_QOS_MIN_DEFAULT_VALUE) {
		struct cpufreq_policy *policy __free(put_cpufreq_policy) =
					      cpufreq_cpu_get(policy_data->cpu);
		struct amd_cpudata *cpudata;
		union perf_cached perf;

		if (!policy)
			return -EINVAL;

		cpudata = policy->driver_data;
		perf = READ_ONCE(cpudata->perf);

		if (perf.bios_min_perf)
			policy_data->min = perf_to_freq(perf, cpudata->nominal_freq,
							perf.bios_min_perf);
		else
			policy_data->min = cpudata->lowest_nonlinear_freq;
	}

@@ -1021,6 +1044,10 @@ static int amd_pstate_cpu_init(struct cpufreq_policy *policy)
static void amd_pstate_cpu_exit(struct cpufreq_policy *policy)
{
	struct amd_cpudata *cpudata = policy->driver_data;
	union perf_cached perf = READ_ONCE(cpudata->perf);

	/* Reset CPPC_REQ MSR to the BIOS value */
	amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);

	freq_qos_remove_request(&cpudata->req[1]);
	freq_qos_remove_request(&cpudata->req[0]);
@@ -1302,6 +1329,12 @@ static ssize_t amd_pstate_show_status(char *buf)
	return sysfs_emit(buf, "%s\n", amd_pstate_mode_string[cppc_state]);
}

int amd_pstate_get_status(void)
{
	return cppc_state;
}
EXPORT_SYMBOL_GPL(amd_pstate_get_status);

int amd_pstate_update_status(const char *buf, size_t size)
{
	int mode_idx;
@@ -1416,7 +1449,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
	struct amd_cpudata *cpudata;
	union perf_cached perf;
	struct device *dev;
	u64 value;
	int ret;

	/*
@@ -1481,12 +1513,6 @@ static int amd_pstate_epp_cpu_init(struct cpufreq_policy *policy)
		cpudata->epp_default = AMD_CPPC_EPP_BALANCE_PERFORMANCE;
	}

	if (cpu_feature_enabled(X86_FEATURE_CPPC)) {
		ret = rdmsrl_on_cpu(cpudata->cpu, MSR_AMD_CPPC_REQ, &value);
		if (ret)
			return ret;
		WRITE_ONCE(cpudata->cppc_req_cached, value);
	}
	ret = amd_pstate_set_epp(policy, cpudata->epp_default);
	if (ret)
		return ret;
@@ -1506,6 +1532,11 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
	struct amd_cpudata *cpudata = policy->driver_data;

	if (cpudata) {
		union perf_cached perf = READ_ONCE(cpudata->perf);

		/* Reset CPPC_REQ MSR to the BIOS value */
		amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);

		kfree(cpudata);
		policy->driver_data = NULL;
	}
@@ -1556,21 +1587,38 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)
	return 0;
}

static int amd_pstate_epp_cpu_online(struct cpufreq_policy *policy)
static int amd_pstate_cpu_online(struct cpufreq_policy *policy)
{
	pr_debug("AMD CPU Core %d going online\n", policy->cpu);

	return amd_pstate_cppc_enable(policy);
}

static int amd_pstate_epp_cpu_offline(struct cpufreq_policy *policy)
static int amd_pstate_cpu_offline(struct cpufreq_policy *policy)
{
	return 0;
	struct amd_cpudata *cpudata = policy->driver_data;
	union perf_cached perf = READ_ONCE(cpudata->perf);

	/*
	 * Reset CPPC_REQ MSR to the BIOS value, this will allow us to retain the BIOS specified
	 * min_perf value across kexec reboots. If this CPU is just onlined normally after this, the
	 * limits, epp and desired perf will get reset to the cached values in cpudata struct
	 */
	return amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
}

static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
static int amd_pstate_suspend(struct cpufreq_policy *policy)
{
	struct amd_cpudata *cpudata = policy->driver_data;
	union perf_cached perf = READ_ONCE(cpudata->perf);
	int ret;

	/*
	 * Reset CPPC_REQ MSR to the BIOS value, this will allow us to retain the BIOS specified
	 * min_perf value across kexec reboots. If this CPU is just resumed back without kexec,
	 * the limits, epp and desired perf will get reset to the cached values in cpudata struct
	 */
	ret = amd_pstate_update_perf(policy, perf.bios_min_perf, 0U, 0U, 0U, false);
	if (ret)
		return ret;

	/* invalidate to ensure it's rewritten during resume */
	cpudata->cppc_req_cached = 0;
@@ -1581,6 +1629,17 @@ static int amd_pstate_epp_suspend(struct cpufreq_policy *policy)
	return 0;
}

static int amd_pstate_resume(struct cpufreq_policy *policy)
{
	struct amd_cpudata *cpudata = policy->driver_data;
	union perf_cached perf = READ_ONCE(cpudata->perf);
	int cur_perf = freq_to_perf(perf, cpudata->nominal_freq, policy->cur);

	/* Set CPPC_REQ to last sane value until the governor updates it */
	return amd_pstate_update_perf(policy, perf.min_limit_perf, cur_perf, perf.max_limit_perf,
				      0U, false);
}

static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
{
	struct amd_cpudata *cpudata = policy->driver_data;
@@ -1606,6 +1665,10 @@ static struct cpufreq_driver amd_pstate_driver = {
	.fast_switch    = amd_pstate_fast_switch,
	.init		= amd_pstate_cpu_init,
	.exit		= amd_pstate_cpu_exit,
	.online		= amd_pstate_cpu_online,
	.offline	= amd_pstate_cpu_offline,
	.suspend	= amd_pstate_suspend,
	.resume		= amd_pstate_resume,
	.set_boost	= amd_pstate_set_boost,
	.update_limits	= amd_pstate_update_limits,
	.name		= "amd-pstate",
@@ -1618,9 +1681,9 @@ static struct cpufreq_driver amd_pstate_epp_driver = {
	.setpolicy	= amd_pstate_epp_set_policy,
	.init		= amd_pstate_epp_cpu_init,
	.exit		= amd_pstate_epp_cpu_exit,
	.offline	= amd_pstate_epp_cpu_offline,
	.online		= amd_pstate_epp_cpu_online,
	.suspend	= amd_pstate_epp_suspend,
	.offline	= amd_pstate_cpu_offline,
	.online		= amd_pstate_cpu_online,
	.suspend	= amd_pstate_suspend,
	.resume		= amd_pstate_epp_resume,
	.update_limits	= amd_pstate_update_limits,
	.set_boost	= amd_pstate_set_boost,
+3 −0
Original line number Diff line number Diff line
@@ -30,6 +30,7 @@
 * @lowest_perf: the absolute lowest performance level of the processor
 * @min_limit_perf: Cached value of the performance corresponding to policy->min
 * @max_limit_perf: Cached value of the performance corresponding to policy->max
 * @bios_min_perf: Cached perf value corresponding to the "Requested CPU Min Frequency" BIOS option
 */
union perf_cached {
	struct {
@@ -39,6 +40,7 @@ union perf_cached {
		u8	lowest_perf;
		u8	min_limit_perf;
		u8	max_limit_perf;
		u8	bios_min_perf;
	};
	u64	val;
};
@@ -119,6 +121,7 @@ enum amd_pstate_mode {
	AMD_PSTATE_MAX,
};
const char *amd_pstate_get_mode_string(enum amd_pstate_mode mode);
int amd_pstate_get_status(void);
int amd_pstate_update_status(const char *buf, size_t size);

#endif /* _LINUX_AMD_PSTATE_H */