Commit 4badf2eb authored by Gautham R. Shenoy's avatar Gautham R. Shenoy Committed by Rafael J. Wysocki
Browse files

cpufreq: amd-pstate: Add ->fast_switch() callback



Schedutil normally calls the adjust_perf callback for drivers with
adjust_perf callback available and fast_switch_possible flag set.
However, when frequency invariance is disabled and schedutil tries to
invoke fast_switch. So, there is a chance of kernel crash if this
function pointer is not set. To protect against this scenario add
fast_switch callback to amd_pstate driver.

Fixes: 1d215f03 ("cpufreq: amd-pstate: Add fast switch function for AMD P-State")
Signed-off-by: default avatarGautham R. Shenoy <gautham.shenoy@amd.com>
Signed-off-by: default avatarWyes Karny <wyes.karny@amd.com>
Signed-off-by: default avatarRafael J. Wysocki <rafael.j.wysocki@intel.com>
parent 44c026a7
Loading
Loading
Loading
Loading
+30 −6
Original line number Diff line number Diff line
@@ -444,9 +444,8 @@ static int amd_pstate_verify(struct cpufreq_policy_data *policy)
	return 0;
}

static int amd_pstate_target(struct cpufreq_policy *policy,
			     unsigned int target_freq,
			     unsigned int relation)
static int amd_pstate_update_freq(struct cpufreq_policy *policy,
				  unsigned int target_freq, bool fast_switch)
{
	struct cpufreq_freqs freqs;
	struct amd_cpudata *cpudata = policy->driver_data;
@@ -465,14 +464,37 @@ static int amd_pstate_target(struct cpufreq_policy *policy,
	des_perf = DIV_ROUND_CLOSEST(target_freq * cap_perf,
				     cpudata->max_freq);

	WARN_ON(fast_switch && !policy->fast_switch_enabled);
	/*
	 * If fast_switch is desired, then there aren't any registered
	 * transition notifiers. See comment for
	 * cpufreq_enable_fast_switch().
	 */
	if (!fast_switch)
		cpufreq_freq_transition_begin(policy, &freqs);

	amd_pstate_update(cpudata, min_perf, des_perf,
			  max_perf, false, policy->governor->flags);
			max_perf, fast_switch, policy->governor->flags);

	if (!fast_switch)
		cpufreq_freq_transition_end(policy, &freqs, false);

	return 0;
}

static int amd_pstate_target(struct cpufreq_policy *policy,
			     unsigned int target_freq,
			     unsigned int relation)
{
	return amd_pstate_update_freq(policy, target_freq, false);
}

static unsigned int amd_pstate_fast_switch(struct cpufreq_policy *policy,
				  unsigned int target_freq)
{
	return amd_pstate_update_freq(policy, target_freq, true);
}

static void amd_pstate_adjust_perf(unsigned int cpu,
				   unsigned long _min_perf,
				   unsigned long target_perf,
@@ -715,6 +737,7 @@ static int amd_pstate_cpu_exit(struct cpufreq_policy *policy)

	freq_qos_remove_request(&cpudata->req[1]);
	freq_qos_remove_request(&cpudata->req[0]);
	policy->fast_switch_possible = false;
	kfree(cpudata);

	return 0;
@@ -1309,6 +1332,7 @@ static struct cpufreq_driver amd_pstate_driver = {
	.flags		= CPUFREQ_CONST_LOOPS | CPUFREQ_NEED_UPDATE_LIMITS,
	.verify		= amd_pstate_verify,
	.target		= amd_pstate_target,
	.fast_switch    = amd_pstate_fast_switch,
	.init		= amd_pstate_cpu_init,
	.exit		= amd_pstate_cpu_exit,
	.suspend	= amd_pstate_cpu_suspend,