PM: EM: Introduce em_adjust_cpu_capacity()
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 6 May 2025 20:41:21 +0000 (22:41 +0200)
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>
Tue, 13 May 2025 12:34:18 +0000 (14:34 +0200)
Add a function for updating the Energy Model for a CPU after its
capacity has changed, which subsequently will be used by the
intel_pstate driver.

An EM_PERF_DOMAIN_ARTIFICIAL check is added to em_recalc_and_update()
to prevent it from calling em_compute_costs() for an "artificial" perf
domain with a NULL cb parameter which would cause it to crash.

Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
Reviewed-by: Lukasz Luba <lukasz.luba@arm.com>
Tested-by: Christian Loehle <christian.loehle@arm.com>
Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Link: https://patch.msgid.link/3637203.iIbC2pHGDl@rjwysocki.net
include/linux/energy_model.h
kernel/power/energy_model.c

index d8eabbf86a5b3156511aff7a36073ee32c2fd007..7fa1eb3cc8239998c04988ff3cee33781c40f967 100644 (file)
@@ -179,6 +179,7 @@ int em_dev_compute_costs(struct device *dev, struct em_perf_state *table,
 int em_dev_update_chip_binning(struct device *dev);
 int em_update_performance_limits(struct em_perf_domain *pd,
                unsigned long freq_min_khz, unsigned long freq_max_khz);
+void em_adjust_cpu_capacity(unsigned int cpu);
 void em_rebuild_sched_domains(void);
 
 /**
@@ -403,6 +404,7 @@ int em_update_performance_limits(struct em_perf_domain *pd,
 {
        return -EINVAL;
 }
+static inline void em_adjust_cpu_capacity(unsigned int cpu) {}
 static inline void em_rebuild_sched_domains(void) {}
 #endif
 
index 88449d4390cb207b8de424b1d7b7eb0d2788ccf7..ea7995a25780f3106b9a87ae7e425746af7da2a5 100644 (file)
@@ -702,10 +702,12 @@ static int em_recalc_and_update(struct device *dev, struct em_perf_domain *pd,
 {
        int ret;
 
-       ret = em_compute_costs(dev, em_table->state, NULL, pd->nr_perf_states,
-                              pd->flags);
-       if (ret)
-               goto free_em_table;
+       if (!em_is_artificial(pd)) {
+               ret = em_compute_costs(dev, em_table->state, NULL,
+                                      pd->nr_perf_states, pd->flags);
+               if (ret)
+                       goto free_em_table;
+       }
 
        ret = em_dev_update_perf_domain(dev, em_table);
        if (ret)
@@ -755,6 +757,24 @@ static void em_adjust_new_capacity(unsigned int cpu, struct device *dev,
        em_recalc_and_update(dev, pd, em_table);
 }
 
+/**
+ * em_adjust_cpu_capacity() - Adjust the EM for a CPU after a capacity update.
+ * @cpu: Target CPU.
+ *
+ * Adjust the existing EM for @cpu after a capacity update under the assumption
+ * that the capacity has been updated in the same way for all of the CPUs in
+ * the same perf domain.
+ */
+void em_adjust_cpu_capacity(unsigned int cpu)
+{
+       struct device *dev = get_cpu_device(cpu);
+       struct em_perf_domain *pd;
+
+       pd = em_pd_get(dev);
+       if (pd)
+               em_adjust_new_capacity(cpu, dev, pd);
+}
+
 static void em_check_capacity_update(void)
 {
        cpumask_var_t cpu_done_mask;