@@ -691,6 +691,14 @@ static inline u32 per_cpu_l2c_id(unsigned int cpu)
return per_cpu(cpu_info.topo.l2c_id, cpu);
}
+/* defined by CPUID_Fn80000026_EBX BIT [31:28] */
+enum amd_core_type {
+ CPU_CORE_TYPE_NO_HETERO_SUP = -1,
+ CPU_CORE_TYPE_PERFORMANCE = 0,
+ CPU_CORE_TYPE_EFFICIENCY = 1,
+ CPU_CORE_TYPE_UNDEFINED = 2,
+};
+
#ifdef CONFIG_CPU_SUP_AMD
/*
* Issue a DIV 0/1 insn to clear any division data from previous DIV
@@ -703,9 +711,14 @@ static __always_inline void amd_clear_divider(void)
}
extern void amd_check_microcode(void);
+extern enum amd_core_type amd_get_core_type(void);
#else
static inline void amd_clear_divider(void) { }
static inline void amd_check_microcode(void) { }
+static inline enum amd_core_type amd_get_core_type(void)
+{
+ return CPU_CORE_TYPE_NO_HETERO_SUP;
+}
#endif
extern unsigned long arch_align_stack(unsigned long sp);
@@ -217,6 +217,12 @@ int amd_detect_prefcore(bool *detected)
}
EXPORT_SYMBOL_GPL(amd_detect_prefcore);
+static void amd_do_get_core_type(void *data)
+{
+ enum amd_core_type *core_type = data;
+ *core_type = amd_get_core_type();
+}
+
/**
* amd_get_boost_ratio_numerator: Get the numerator to use for boost ratio calculation
* @cpu: CPU to get numerator for.
@@ -234,7 +240,9 @@ EXPORT_SYMBOL_GPL(amd_detect_prefcore);
*/
int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
{
+ enum amd_core_type core_type;
bool prefcore;
+ u32 tmp;
int ret;
ret = amd_detect_prefcore(&prefcore);
@@ -261,6 +269,28 @@ int amd_get_boost_ratio_numerator(unsigned int cpu, u64 *numerator)
break;
}
}
+
+ /* detect if running on heterogeneous design */
+ smp_call_function_single(cpu, amd_do_get_core_type, &core_type, 1);
+ switch (core_type) {
+ case CPU_CORE_TYPE_NO_HETERO_SUP:
+ break;
+ case CPU_CORE_TYPE_PERFORMANCE:
+ /* use the max scale for performance cores */
+ *numerator = CPPC_HIGHEST_PERF_PERFORMANCE;
+ return 0;
+ case CPU_CORE_TYPE_EFFICIENCY:
+ /* use the highest perf value for efficiency cores */
+ ret = amd_get_highest_perf(cpu, &tmp);
+ if (ret)
+ return ret;
+ *numerator = tmp;
+ return 0;
+ default:
+ pr_warn("WARNING: Undefined core type %d found\n", core_type);
+ break;
+ }
+
*numerator = CPPC_HIGHEST_PERF_PREFCORE;
return 0;
@@ -1204,3 +1204,32 @@ void amd_check_microcode(void)
on_each_cpu(zenbleed_check_cpu, NULL, 1);
}
+
+/**
+ * amd_get_core_type - Heterogeneous core type identification
+ *
+ * Returns the CPU type [31:28] (i.e., performance or efficient) of
+ * a CPU in the processor.
+ *
+ * If the processor has no core type support, returns
+ * CPU_CORE_TYPE_NO_HETERO_SUP.
+ */
+enum amd_core_type amd_get_core_type(void)
+{
+ struct {
+ u32 num_processors :16,
+ power_efficiency_ranking :8,
+ native_model_id :4,
+ core_type :4;
+ } props;
+
+ if (!cpu_feature_enabled(X86_FEATURE_HETERO_CORE_TOPOLOGY))
+ return CPU_CORE_TYPE_NO_HETERO_SUP;
+
+ cpuid_leaf_reg(0x80000026, CPUID_EBX, &props);
+ if (props.core_type >= CPU_CORE_TYPE_UNDEFINED)
+ return CPU_CORE_TYPE_UNDEFINED;
+
+ return props.core_type;
+}
+EXPORT_SYMBOL_GPL(amd_get_core_type);