===================================================================
@@ -943,6 +943,62 @@ static struct cpudata *hybrid_max_perf_c
*/
static DEFINE_MUTEX(hybrid_capacity_lock);
+#ifdef CONFIG_ENERGY_MODEL
+/*
+ * A hybrid domain is a collection of CPUs with the same perf-to-frequency
+ * scaling factor.
+ */
+struct hybrid_domain {
+ struct hybrid_domain *next;
+ cpumask_t cpumask;
+ int scaling;
+};
+
+static struct hybrid_domain *hybrid_domains;
+
+static void hybrid_add_to_domain(struct cpudata *cpudata)
+{
+ int scaling = cpudata->pstate.scaling;
+ int cpu = cpudata->cpu;
+ struct hybrid_domain *hd;
+
+ /* Do this only on hubrid platforms. */
+ if (!cpu_feature_enabled(X86_FEATURE_HYBRID_CPU))
+ return;
+
+ guard(mutex)(&hybrid_capacity_lock);
+
+ /* Look for an existing hybrid domain matching this CPU. */
+ for (hd = hybrid_domains; hd; hd = hd->next) {
+ if (hd->scaling == scaling) {
+ if (cpumask_test_cpu(cpu, &hd->cpumask))
+ return;
+
+ cpumask_set_cpu(cpu, &hd->cpumask);
+
+ pr_debug("CPU %d added to hybrid domain %*pbl\n", cpu,
+ cpumask_pr_args(&hd->cpumask));
+ return;
+ }
+ }
+
+ /* No match. Add a new one. */
+ hd = kzalloc(sizeof(*hd), GFP_KERNEL);
+ if (!hd)
+ return;
+
+ cpumask_set_cpu(cpu, &hd->cpumask);
+ hd->scaling = scaling;
+ hd->next = hybrid_domains;
+ hybrid_domains = hd;
+
+ pr_debug("New hybrid domain %*pbl: scaling = %d\n",
+ cpumask_pr_args(&hd->cpumask), hd->scaling);
+}
+#else /* CONFIG_ENERGY_MODEL */
+static inline void hybrid_add_to_domain(struct cpudata *cpudata) {}
+#endif /* !CONFIG_ENERGY_MODEL */
+
static void hybrid_set_cpu_capacity(struct cpudata *cpu)
{
arch_set_cpu_capacity(cpu->cpu, cpu->capacity_perf,
@@ -2273,6 +2329,7 @@ static void intel_pstate_get_cpu_pstates
intel_pstate_hybrid_hwp_adjust(cpu);
hwp_is_hybrid = true;
}
+ hybrid_add_to_domain(cpu);
} else {
cpu->pstate.scaling = perf_ctl_scaling;
}