mirror of https://github.com/torvalds/linux.git
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>
This commit is contained in:
parent
211ddde082
commit
cbe5aeedec
|
|
@ -54,6 +54,8 @@ struct em_perf_table {
|
||||||
/**
|
/**
|
||||||
* struct em_perf_domain - Performance domain
|
* struct em_perf_domain - Performance domain
|
||||||
* @em_table: Pointer to the runtime modifiable em_perf_table
|
* @em_table: Pointer to the runtime modifiable em_perf_table
|
||||||
|
* @node: node in em_pd_list (in energy_model.c)
|
||||||
|
* @id: A unique ID number for each performance domain
|
||||||
* @nr_perf_states: Number of performance states
|
* @nr_perf_states: Number of performance states
|
||||||
* @min_perf_state: Minimum allowed Performance State index
|
* @min_perf_state: Minimum allowed Performance State index
|
||||||
* @max_perf_state: Maximum allowed Performance State index
|
* @max_perf_state: Maximum allowed Performance State index
|
||||||
|
|
@ -71,6 +73,8 @@ struct em_perf_table {
|
||||||
*/
|
*/
|
||||||
struct em_perf_domain {
|
struct em_perf_domain {
|
||||||
struct em_perf_table __rcu *em_table;
|
struct em_perf_table __rcu *em_table;
|
||||||
|
struct list_head node;
|
||||||
|
int id;
|
||||||
int nr_perf_states;
|
int nr_perf_states;
|
||||||
int min_perf_state;
|
int min_perf_state;
|
||||||
int max_perf_state;
|
int max_perf_state;
|
||||||
|
|
|
||||||
|
|
@ -23,6 +23,16 @@
|
||||||
*/
|
*/
|
||||||
static DEFINE_MUTEX(em_pd_mutex);
|
static DEFINE_MUTEX(em_pd_mutex);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Manage performance domains with IDs. One can iterate the performance domains
|
||||||
|
* through the list and pick one with their associated ID. The mutex serializes
|
||||||
|
* the list access. When holding em_pd_list_mutex, em_pd_mutex should not be
|
||||||
|
* taken to avoid potential deadlock.
|
||||||
|
*/
|
||||||
|
static DEFINE_IDA(em_pd_ida);
|
||||||
|
static LIST_HEAD(em_pd_list);
|
||||||
|
static DEFINE_MUTEX(em_pd_list_mutex);
|
||||||
|
|
||||||
static void em_cpufreq_update_efficiencies(struct device *dev,
|
static void em_cpufreq_update_efficiencies(struct device *dev,
|
||||||
struct em_perf_state *table);
|
struct em_perf_state *table);
|
||||||
static void em_check_capacity_update(void);
|
static void em_check_capacity_update(void);
|
||||||
|
|
@ -396,7 +406,7 @@ static int em_create_pd(struct device *dev, int nr_states,
|
||||||
struct em_perf_table *em_table;
|
struct em_perf_table *em_table;
|
||||||
struct em_perf_domain *pd;
|
struct em_perf_domain *pd;
|
||||||
struct device *cpu_dev;
|
struct device *cpu_dev;
|
||||||
int cpu, ret, num_cpus;
|
int cpu, ret, num_cpus, id;
|
||||||
|
|
||||||
if (_is_cpu_device(dev)) {
|
if (_is_cpu_device(dev)) {
|
||||||
num_cpus = cpumask_weight(cpus);
|
num_cpus = cpumask_weight(cpus);
|
||||||
|
|
@ -420,6 +430,13 @@ static int em_create_pd(struct device *dev, int nr_states,
|
||||||
|
|
||||||
pd->nr_perf_states = nr_states;
|
pd->nr_perf_states = nr_states;
|
||||||
|
|
||||||
|
INIT_LIST_HEAD(&pd->node);
|
||||||
|
|
||||||
|
id = ida_alloc(&em_pd_ida, GFP_KERNEL);
|
||||||
|
if (id < 0)
|
||||||
|
return -ENOMEM;
|
||||||
|
pd->id = id;
|
||||||
|
|
||||||
em_table = em_table_alloc(pd);
|
em_table = em_table_alloc(pd);
|
||||||
if (!em_table)
|
if (!em_table)
|
||||||
goto free_pd;
|
goto free_pd;
|
||||||
|
|
@ -444,6 +461,7 @@ static int em_create_pd(struct device *dev, int nr_states,
|
||||||
kfree(em_table);
|
kfree(em_table);
|
||||||
free_pd:
|
free_pd:
|
||||||
kfree(pd);
|
kfree(pd);
|
||||||
|
ida_free(&em_pd_ida, id);
|
||||||
return -EINVAL;
|
return -EINVAL;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -660,6 +678,10 @@ int em_dev_register_pd_no_update(struct device *dev, unsigned int nr_states,
|
||||||
unlock:
|
unlock:
|
||||||
mutex_unlock(&em_pd_mutex);
|
mutex_unlock(&em_pd_mutex);
|
||||||
|
|
||||||
|
mutex_lock(&em_pd_list_mutex);
|
||||||
|
list_add_tail(&dev->em_pd->node, &em_pd_list);
|
||||||
|
mutex_unlock(&em_pd_list_mutex);
|
||||||
|
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update);
|
EXPORT_SYMBOL_GPL(em_dev_register_pd_no_update);
|
||||||
|
|
@ -678,6 +700,10 @@ void em_dev_unregister_perf_domain(struct device *dev)
|
||||||
if (_is_cpu_device(dev))
|
if (_is_cpu_device(dev))
|
||||||
return;
|
return;
|
||||||
|
|
||||||
|
mutex_lock(&em_pd_list_mutex);
|
||||||
|
list_del_init(&dev->em_pd->node);
|
||||||
|
mutex_unlock(&em_pd_list_mutex);
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* The mutex separates all register/unregister requests and protects
|
* The mutex separates all register/unregister requests and protects
|
||||||
* from potential clean-up/setup issues in the debugfs directories.
|
* from potential clean-up/setup issues in the debugfs directories.
|
||||||
|
|
@ -689,6 +715,8 @@ void em_dev_unregister_perf_domain(struct device *dev)
|
||||||
em_table_free(rcu_dereference_protected(dev->em_pd->em_table,
|
em_table_free(rcu_dereference_protected(dev->em_pd->em_table,
|
||||||
lockdep_is_held(&em_pd_mutex)));
|
lockdep_is_held(&em_pd_mutex)));
|
||||||
|
|
||||||
|
ida_free(&em_pd_ida, dev->em_pd->id);
|
||||||
|
|
||||||
kfree(dev->em_pd);
|
kfree(dev->em_pd);
|
||||||
dev->em_pd = NULL;
|
dev->em_pd = NULL;
|
||||||
mutex_unlock(&em_pd_mutex);
|
mutex_unlock(&em_pd_mutex);
|
||||||
|
|
|
||||||
Loading…
Reference in New Issue