Skip to content

Commit cbe5aee

Browse files
multics69rafaeljw
authored andcommitted
PM: EM: Assign a unique ID when creating a performance domain
It is necessary to refer to a specific performance domain from a userspace. For example, the energy model of a particular performance domain is updated. To this end, assign a unique ID to each performance domain to address it, and manage them in a global linked list to look up a specific one by matching ID. IDA is used for ID assignment, and the mutex is used to protect the global list from concurrent access. Note that the mutex (em_pd_list_mutex) is not supposed to hold while holding em_pd_mutex to avoid ABBA deadlock. Signed-off-by: Changwoo Min <changwoo@igalia.com> Reviewed-by: Lukasz Luba <lukasz.luba@arm.com> Link: https://patch.msgid.link/20251020220914.320832-2-changwoo@igalia.com Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
1 parent 211ddde commit cbe5aee

2 files changed

Lines changed: 33 additions & 1 deletion

File tree

include/linux/energy_model.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -54,6 +54,8 @@ struct em_perf_table {
5454
/**
5555
* struct em_perf_domain - Performance domain
5656
* @em_table: Pointer to the runtime modifiable em_perf_table
57+
* @node: node in em_pd_list (in energy_model.c)
58+
* @id: A unique ID number for each performance domain
5759
* @nr_perf_states: Number of performance states
5860
* @min_perf_state: Minimum allowed Performance State index
5961
* @max_perf_state: Maximum allowed Performance State index
@@ -71,6 +73,8 @@ struct em_perf_table {
7173
*/
7274
struct em_perf_domain {
7375
struct em_perf_table __rcu *em_table;
76+
struct list_head node;
77+
int id;
7478
int nr_perf_states;
7579
int min_perf_state;
7680
int max_perf_state;

kernel/power/energy_model.c

Lines changed: 29 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,16 @@
2323
*/
2424
static DEFINE_MUTEX(em_pd_mutex);
2525

26+
/*
27+
* Manage performance domains with IDs. One can iterate the performance domains
28+
* through the list and pick one with their associated ID. The mutex serializes
29+
* the list access. When holding em_pd_list_mutex, em_pd_mutex should not be
30+
* taken to avoid potential deadlock.
31+
*/
32+
static DEFINE_IDA(em_pd_ida);
33+
static LIST_HEAD(em_pd_list);
34+
static DEFINE_MUTEX(em_pd_list_mutex);
35+
2636
static void em_cpufreq_update_efficiencies(struct device *dev,
2737
struct em_perf_state *table);
2838
static void em_check_capacity_update(void);
@@ -396,7 +406,7 @@ static int em_create_pd(struct device *dev, int nr_states,
396406
struct em_perf_table *em_table;
397407
struct em_perf_domain *pd;
398408
struct device *cpu_dev;
399-
int cpu, ret, num_cpus;
409+
int cpu, ret, num_cpus, id;
400410

401411
if (_is_cpu_device(dev)) {
402412
num_cpus = cpumask_weight(cpus);
@@ -420,6 +430,13 @@ static int em_create_pd(struct device *dev, int nr_states,
420430

421431
pd->nr_perf_states = nr_states;
422432

433+
INIT_LIST_HEAD(&pd->node);
434+
435+
id = ida_alloc(&em_pd_ida, GFP_KERNEL);
436+
if (id < 0)
437+
return -ENOMEM;
438+
pd->id = id;
439+
423440
em_table = em_table_alloc(pd);
424441
if (!em_table)
425442
goto free_pd;
@@ -444,6 +461,7 @@ static int em_create_pd(struct device *dev, int nr_states,
444461
kfree(em_table);
445462
free_pd:
446463
kfree(pd);
464+
ida_free(&em_pd_ida, id);
447465
return -EINVAL;
448466
}
449467

@@ -660,6 +678,10 @@ int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
660678
unlock:
661679
mutex_unlock(&em_pd_mutex);
662680

681+
mutex_lock(&em_pd_list_mutex);
682+
list_add_tail(&dev->em_pd->node, &em_pd_list);
683+
mutex_unlock(&em_pd_list_mutex);
684+
663685
return ret;
664686
}
665687
EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update);
@@ -678,6 +700,10 @@ void em_dev_unregister_perf_domain(struct device *dev)
678700
if (_is_cpu_device(dev))
679701
return;
680702

703+
mutex_lock(&em_pd_list_mutex);
704+
list_del_init(&dev->em_pd->node);
705+
mutex_unlock(&em_pd_list_mutex);
706+
681707
/*
682708
* The mutex separates all register/unregister requests and protects
683709
* from potential clean-up/setup issues in the debugfs directories.
@@ -689,6 +715,8 @@ void em_dev_unregister_perf_domain(struct device *dev)
689715
em_table_free(rcu_dereference_protected(dev->em_pd->em_table,
690716
lockdep_is_held(&em_pd_mutex)));
691717

718+
ida_free(&em_pd_ida, dev->em_pd->id);
719+
692720
kfree(dev->em_pd);
693721
dev->em_pd = NULL;
694722
mutex_unlock(&em_pd_mutex);

0 commit comments

Comments
 (0)