Skip to content

Commit

Permalink
PM: EM: Introduce em_dev_update_perf_domain() for EM updates
Browse files Browse the repository at this point in the history
Add API function em_dev_update_perf_domain() which allows the EM to be
changed safely.

Concurrent updaters are serialized with a mutex and the removal of memory
that will not be used any more is carried out with the help of RCU.

Reviewed-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Tested-by: Dietmar Eggemann <dietmar.eggemann@arm.com>
Signed-off-by: Lukasz Luba <lukasz.luba@arm.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
  • Loading branch information
Lukasz Luba authored and Rafael J. Wysocki committed Feb 8, 2024
1 parent ffcf9bc commit 977230d
Show file tree
Hide file tree
Showing 2 changed files with 52 additions and 0 deletions.
8 changes: 8 additions & 0 deletions include/linux/energy_model.h
Original file line number Diff line number Diff line change
Expand Up @@ -183,6 +183,8 @@ struct em_data_callback {

struct em_perf_domain *em_cpu_get(int cpu);
struct em_perf_domain *em_pd_get(struct device *dev);
int em_dev_update_perf_domain(struct device *dev,
struct em_perf_table __rcu *new_table);
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
struct em_data_callback *cb, cpumask_t *span,
bool microwatts);
Expand Down Expand Up @@ -376,6 +378,12 @@ struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
return NULL;
}
static inline void em_table_free(struct em_perf_table __rcu *table) {}
static inline
int em_dev_update_perf_domain(struct device *dev,
struct em_perf_table __rcu *new_table)
{
return -EINVAL;
}
#endif

#endif
44 changes: 44 additions & 0 deletions kernel/power/energy_model.c
Original file line number Diff line number Diff line change
Expand Up @@ -209,6 +209,50 @@ static int em_allocate_perf_table(struct em_perf_domain *pd,
return 0;
}

/**
* em_dev_update_perf_domain() - Update runtime EM table for a device
* @dev : Device for which the EM is to be updated
* @new_table : The new EM table that is going to be used from now
*
* Update EM runtime modifiable table for the @dev using the provided @table.
*
* This function uses a mutex to serialize writers, so it must not be called
* from a non-sleeping context.
*
* Return 0 on success or an error code on failure.
*/
int em_dev_update_perf_domain(struct device *dev,
struct em_perf_table __rcu *new_table)
{
struct em_perf_table __rcu *old_table;
struct em_perf_domain *pd;

if (!dev)
return -EINVAL;

/* Serialize update/unregister or concurrent updates */
mutex_lock(&em_pd_mutex);

if (!dev->em_pd) {
mutex_unlock(&em_pd_mutex);
return -EINVAL;
}
pd = dev->em_pd;

kref_get(&new_table->kref);

old_table = pd->em_table;
rcu_assign_pointer(pd->em_table, new_table);

em_cpufreq_update_efficiencies(dev, new_table->state);

em_table_free(old_table);

mutex_unlock(&em_pd_mutex);
return 0;
}
EXPORT_SYMBOL_GPL(em_dev_update_perf_domain);

static int em_create_runtime_table(struct em_perf_domain *pd)
{
struct em_perf_table __rcu *table;
Expand Down

0 comments on commit 977230d

Please sign in to comment.