Commit 415dff1c authored by Rafael J. Wysocki's avatar Rafael J. Wysocki
Browse files

Merge branch 'pm-cpufreq'

Merge cpufreq updates for 6.12-rc1:

 - Remove LATENCY_MULTIPLIER from cpufreq (Qais Yousef).

 - Add support for Granite Rapids and Sierra Forest in OOB mode to the
   intel_pstate cpufreq driver (Srinivas Pandruvada).

 - Add basic support for CPU capacity scaling on x86 and make the
   intel_pstate driver set asymmetric CPU capacity on hybrid systems
   without SMT (Rafael Wysocki).

 - Add missing MODULE_DESCRIPTION() macros to the powerpc cpufreq
   driver (Jeff Johnson).

 - Several OF related cleanups in cpufreq drivers (Rob Herring).

 - Enable COMPILE_TEST for ARM drivers (Rob Herrring).

 - Introduce quirks for syscon failures and use socinfo to get revision
   for TI cpufreq driver (Dhruva Gole, Nishanth Menon).

 - Minor cleanups in amd-pstate driver (Anastasia Belova, Dhananjay
   Ugwekar).

 - Minor cleanups for loongson, cpufreq-dt and powernv cpufreq drivers
   (Danila Tikhonov, Huacai Chen, and Liu Jing).

 - Make amd-pstate validate return of any attempt to update EPP limits,
   which fixes the masking hardware problems (Mario Limonciello).

 - Move the calculation of the AMD boost numerator outside of amd-pstate,
   correcting acpi-cpufreq on systems with preferred cores (Mario
   Limonciello).

 - Harden preferred core detection in amd-pstate to avoid potential
   false positives (Mario Limonciello).

 - Add extra unit test coverage for mode state machine (Mario
   Limonciello).

 - Fix an "Uninitialized variables" issue in amd-pstste (Qianqiang Liu).

* pm-cpufreq: (35 commits)
  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
  cpufreq/amd-pstate: Catch failures for amd_pstate_epp_update_limit()
  cpufreq: ti-cpufreq: Use socinfo to get revision in AM62 family
  cpufreq: Fix the cacography in powernv-cpufreq.c
  cpufreq: ti-cpufreq: Introduce quirks to handle syscon fails appropriately
  cpufreq: loongson3: Use raw_smp_processor_id() in do_service_request()
  cpufreq: amd-pstate: add check for cpufreq_cpu_get's return value
  ...
parents 83710aaf 9bcf3034
Loading
Loading
Loading
Loading
+14 −1
Original line number Diff line number Diff line
@@ -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
+0 −3
Original line number Diff line number Diff line
@@ -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
+13 −0
Original line number Diff line number Diff line
@@ -282,9 +282,22 @@ static inline long arch_scale_freq_capacity(int cpu)
}
#define arch_scale_freq_capacity arch_scale_freq_capacity

bool arch_enable_hybrid_capacity_scale(void);
void arch_set_cpu_capacity(int cpu, unsigned long cap, unsigned long max_cap,
			   unsigned long cap_freq, unsigned long base_freq);

unsigned long arch_scale_cpu_capacity(int cpu);
#define arch_scale_cpu_capacity arch_scale_cpu_capacity

extern void arch_set_max_freq_ratio(bool turbo_disabled);
extern void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled);
#else
static inline bool arch_enable_hybrid_capacity_scale(void) { return false; }
static inline void arch_set_cpu_capacity(int cpu, unsigned long cap,
					 unsigned long max_cap,
					 unsigned long cap_freq,
					 unsigned long base_freq) { }

static inline void arch_set_max_freq_ratio(bool turbo_disabled) { }
static inline void freq_invariance_set_perf_ratio(u64 ratio, bool turbo_disabled) { }
#endif
+161 −11
Original line number Diff line number Diff line
@@ -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);
+0 −16
Original line number Diff line number Diff line
@@ -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());
Loading