Commit a1228f04 authored by Linus Torvalds's avatar Linus Torvalds
Browse files
Pull power management fixes from Rafael Wysocki:
 "These fix a nasty hibernation regression introduced during the 6.16
  cycle, an issue related to energy model management occurring on Intel
  hybrid systems where some CPUs are offline to start with, and two
  regressions in the amd-pstate driver:

   - Restore a pm_restrict_gfp_mask() call in hibernation_snapshot()
     that was removed incorrectly during the 6.16 development cycle
     (Rafael Wysocki)

   - Introduce a function for registering a perf domain without
     triggering a system-wide CPU capacity update and make the
     intel_pstate driver use it to avoid reocurring unsuccessful
     attempts to update capacities of all CPUs in the system (Rafael
     Wysocki)

   - Fix setting of CPPC.min_perf in the active mode with performance
     governor in the amd-pstate driver to restore its expected behavior
     changed recently (Gautham Shenoy)

   - Avoid mistakenly setting EPP to 0 in the amd-pstate driver after
     system resume as a result of recent code changes (Mario
     Limonciello)"

* tag 'pm-6.17-rc6' of git://git.kernel.org/pub/scm/linux/kernel/git/rafael/linux-pm:
  PM: hibernate: Restrict GFP mask in hibernation_snapshot()
  PM: EM: Add function for registering a PD without capacity update
  cpufreq/amd-pstate: Fix a regression leading to EPP 0 after resume
  cpufreq/amd-pstate: Fix setting of CPPC.min_perf in active mode for performance governor
parents b10c31b7 bddce1c7
Loading
Loading
Loading
Loading
+11 −8
Original line number Diff line number Diff line
@@ -1554,13 +1554,15 @@ static void amd_pstate_epp_cpu_exit(struct cpufreq_policy *policy)
	pr_debug("CPU %d exiting\n", policy->cpu);
}

static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy)
static int amd_pstate_epp_update_limit(struct cpufreq_policy *policy, bool policy_change)
{
	struct amd_cpudata *cpudata = policy->driver_data;
	union perf_cached perf;
	u8 epp;

	if (policy->min != cpudata->min_limit_freq || policy->max != cpudata->max_limit_freq)
	if (policy_change ||
	    policy->min != cpudata->min_limit_freq ||
	    policy->max != cpudata->max_limit_freq)
		amd_pstate_update_min_max_limit(policy);

	if (cpudata->policy == CPUFREQ_POLICY_PERFORMANCE)
@@ -1584,7 +1586,7 @@ static int amd_pstate_epp_set_policy(struct cpufreq_policy *policy)

	cpudata->policy = policy->policy;

	ret = amd_pstate_epp_update_limit(policy);
	ret = amd_pstate_epp_update_limit(policy, true);
	if (ret)
		return ret;

@@ -1626,13 +1628,14 @@ static int amd_pstate_suspend(struct cpufreq_policy *policy)
	 * 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);
	ret = amd_pstate_update_perf(policy, perf.bios_min_perf,
				     FIELD_GET(AMD_CPPC_DES_PERF_MASK, cpudata->cppc_req_cached),
				     FIELD_GET(AMD_CPPC_MAX_PERF_MASK, cpudata->cppc_req_cached),
				     FIELD_GET(AMD_CPPC_EPP_PERF_MASK, cpudata->cppc_req_cached),
				     false);
	if (ret)
		return ret;

	/* invalidate to ensure it's rewritten during resume */
	cpudata->cppc_req_cached = 0;

	/* set this flag to avoid setting core offline*/
	cpudata->suspended = true;

@@ -1658,7 +1661,7 @@ static int amd_pstate_epp_resume(struct cpufreq_policy *policy)
		int ret;

		/* enable amd pstate from suspend state*/
		ret = amd_pstate_epp_update_limit(policy);
		ret = amd_pstate_epp_update_limit(policy, false);
		if (ret)
			return ret;

+2 −2
Original line number Diff line number Diff line
@@ -1034,7 +1034,7 @@ static bool hybrid_register_perf_domain(unsigned int cpu)
	if (!cpu_dev)
		return false;

	if (em_dev_register_perf_domain(cpu_dev, HYBRID_EM_STATE_COUNT, &cb,
	if (em_dev_register_pd_no_update(cpu_dev, HYBRID_EM_STATE_COUNT, &cb,
					 cpumask_of(cpu), false))
		return false;

+10 −0
Original line number Diff line number Diff line
@@ -171,6 +171,9 @@ int em_dev_update_perf_domain(struct device *dev,
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
				const struct em_data_callback *cb,
				const cpumask_t *cpus, bool microwatts);
int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
				 const struct em_data_callback *cb,
				 const cpumask_t *cpus, bool microwatts);
void em_dev_unregister_perf_domain(struct device *dev);
struct em_perf_table *em_table_alloc(struct em_perf_domain *pd);
void em_table_free(struct em_perf_table *table);
@@ -350,6 +353,13 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
{
	return -EINVAL;
}
static inline
int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
				 const struct em_data_callback *cb,
				 const cpumask_t *cpus, bool microwatts)
{
	return -EINVAL;
}
static inline void em_dev_unregister_perf_domain(struct device *dev)
{
}
+25 −4
Original line number Diff line number Diff line
@@ -552,6 +552,30 @@ EXPORT_SYMBOL_GPL(em_cpu_get);
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
				const struct em_data_callback *cb,
				const cpumask_t *cpus, bool microwatts)
{
	int ret = em_dev_register_pd_no_update(dev, nr_states, cb, cpus, microwatts);

	if (_is_cpu_device(dev))
		em_check_capacity_update();

	return ret;
}
EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);

/**
 * em_dev_register_pd_no_update() - Register a perf domain for a device
 * @dev : Device to register the PD for
 * @nr_states : Number of performance states in the new PD
 * @cb : Callback functions for populating the energy model
 * @cpus : CPUs to include in the new PD (mandatory if @dev is a CPU device)
 * @microwatts : Whether or not the power values in the EM will be in uW
 *
 * Like em_dev_register_perf_domain(), but does not trigger a CPU capacity
 * update after registering the PD, even if @dev is a CPU device.
 */
int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
				 const struct em_data_callback *cb,
				 const cpumask_t *cpus, bool microwatts)
{
	struct em_perf_table *em_table;
	unsigned long cap, prev_cap = 0;
@@ -636,12 +660,9 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
unlock:
	mutex_unlock(&em_pd_mutex);

	if (_is_cpu_device(dev))
		em_check_capacity_update();

	return ret;
}
EXPORT_SYMBOL_GPL(em_dev_register_perf_domain);
EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update);

/**
 * em_dev_unregister_perf_domain() - Unregister Energy Model (EM) for a device
+1 −0
Original line number Diff line number Diff line
@@ -449,6 +449,7 @@ int hibernation_snapshot(int platform_mode)
	shrink_shmem_memory();

	console_suspend_all();
	pm_restrict_gfp_mask();

	error = dpm_suspend(PMSG_FREEZE);