PM: EM: Introduce em_dev_update_perf_domain() for EM updates
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>
This commit is contained in:
parent
ffcf9bce7a
commit
977230d5d5
|
@ -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);
|
||||
|
@ -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
|
||||
|
|
|
@ -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;
|
||||
|
|
Loading…
Reference in New Issue