+/**
+ * em_rescale_cpu_capacity() - Re-scale capacity values of the Energy Model
+ *
+ * This re-scales the capacity values for all capacity states of all frequency
+ * domains of the Energy Model. This should be used when the capacity values
+ * of the CPUs are updated at run-time, after the EM was registered.
+ */
+void em_rescale_cpu_capacity(void)
+{
+ struct em_cs_table *old_table, *new_table;
+ struct em_freq_domain *fd;
+ int nr_states, cpu;
+
+ mutex_lock(&em_fd_mutex);
+ rcu_read_lock();
+ for_each_possible_cpu(cpu) {
+ /* Re-scale only once per frequency domain. */
+ fd = READ_ONCE(per_cpu(em_data, cpu));
+ if (!fd || cpu != cpumask_first(to_cpumask(fd->cpus)))
+ continue;
+
+ /* Copy the existing table. */
+ old_table = rcu_dereference(fd->cs_table);
+ nr_states = old_table->nr_cap_states;
+ new_table = alloc_cs_table(nr_states);
+ if (!new_table)
+ goto out;
+ memcpy(new_table->state, old_table->state,
+ nr_states * sizeof(*new_table->state));
+
+ /* Re-scale the capacity values of the copy. */
+ fd_update_cs_table(new_table,
+ cpumask_first(to_cpumask(fd->cpus)));
+
+ /* Replace the fd table with the re-scaled version. */
+ rcu_assign_pointer(fd->cs_table, new_table);
+ call_rcu(&old_table->rcu, rcu_free_cs_table);
+ }
+out:
+ rcu_read_unlock();
+ mutex_unlock(&em_fd_mutex);
+}
+EXPORT_SYMBOL_GPL(em_rescale_cpu_capacity);