Skip to content

Commit 977230d

Browse files
lukaszluba-armrafaeljw
authored andcommitted
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 <[email protected]> Tested-by: Dietmar Eggemann <[email protected]> Signed-off-by: Lukasz Luba <[email protected]> Signed-off-by: Rafael J. Wysocki <[email protected]>
1 parent ffcf9bc commit 977230d

File tree

2 files changed

+52
-0
lines changed

2 files changed

+52
-0
lines changed

include/linux/energy_model.h

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -183,6 +183,8 @@ struct em_data_callback {
183183

184184
struct em_perf_domain *em_cpu_get(int cpu);
185185
struct em_perf_domain *em_pd_get(struct device *dev);
186+
int em_dev_update_perf_domain(struct device *dev,
187+
struct em_perf_table __rcu *new_table);
186188
int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
187189
struct em_data_callback *cb, cpumask_t *span,
188190
bool microwatts);
@@ -376,6 +378,12 @@ struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
376378
return NULL;
377379
}
378380
static inline void em_table_free(struct em_perf_table __rcu *table) {}
381+
static inline
382+
int em_dev_update_perf_domain(struct device *dev,
383+
struct em_perf_table __rcu *new_table)
384+
{
385+
return -EINVAL;
386+
}
379387
#endif
380388

381389
#endif

kernel/power/energy_model.c

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -209,6 +209,50 @@ static int em_allocate_perf_table(struct em_perf_domain *pd,
209209
return 0;
210210
}
211211

212+
/**
213+
* em_dev_update_perf_domain() - Update runtime EM table for a device
214+
* @dev : Device for which the EM is to be updated
215+
* @new_table : The new EM table that is going to be used from now
216+
*
217+
* Update EM runtime modifiable table for the @dev using the provided @table.
218+
*
219+
* This function uses a mutex to serialize writers, so it must not be called
220+
* from a non-sleeping context.
221+
*
222+
* Return 0 on success or an error code on failure.
223+
*/
224+
int em_dev_update_perf_domain(struct device *dev,
225+
struct em_perf_table __rcu *new_table)
226+
{
227+
struct em_perf_table __rcu *old_table;
228+
struct em_perf_domain *pd;
229+
230+
if (!dev)
231+
return -EINVAL;
232+
233+
/* Serialize update/unregister or concurrent updates */
234+
mutex_lock(&em_pd_mutex);
235+
236+
if (!dev->em_pd) {
237+
mutex_unlock(&em_pd_mutex);
238+
return -EINVAL;
239+
}
240+
pd = dev->em_pd;
241+
242+
kref_get(&new_table->kref);
243+
244+
old_table = pd->em_table;
245+
rcu_assign_pointer(pd->em_table, new_table);
246+
247+
em_cpufreq_update_efficiencies(dev, new_table->state);
248+
249+
em_table_free(old_table);
250+
251+
mutex_unlock(&em_pd_mutex);
252+
return 0;
253+
}
254+
EXPORT_SYMBOL_GPL(em_dev_update_perf_domain);
255+
212256
static int em_create_runtime_table(struct em_perf_domain *pd)
213257
{
214258
struct em_perf_table __rcu *table;

0 commit comments

Comments
 (0)