Skip to content

Commit ffcf9bc

Browse files
lukaszluba-armrafaeljw
authored andcommitted
PM: EM: Add functions for memory allocations for new EM tables
The runtime modified EM table can be provided from drivers. Create mechanism which allows safely allocate and free the table for device drivers. The same table can be used by the EAS in task scheduler code paths, so make sure the memory is not freed when the device driver module is unloaded. 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 aa11a7e commit ffcf9bc

File tree

2 files changed

+44
-5
lines changed

2 files changed

+44
-5
lines changed

include/linux/energy_model.h

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5,6 +5,7 @@
55
#include <linux/device.h>
66
#include <linux/jump_label.h>
77
#include <linux/kobject.h>
8+
#include <linux/kref.h>
89
#include <linux/rcupdate.h>
910
#include <linux/sched/cpufreq.h>
1011
#include <linux/sched/topology.h>
@@ -39,10 +40,12 @@ struct em_perf_state {
3940
/**
4041
* struct em_perf_table - Performance states table
4142
* @rcu: RCU used for safe access and destruction
43+
* @kref: Reference counter to track the users
4244
* @state: List of performance states, in ascending order
4345
*/
4446
struct em_perf_table {
4547
struct rcu_head rcu;
48+
struct kref kref;
4649
struct em_perf_state state[];
4750
};
4851

@@ -184,6 +187,8 @@ int em_dev_register_perf_domain(struct device *dev, unsigned int nr_states,
184187
struct em_data_callback *cb, cpumask_t *span,
185188
bool microwatts);
186189
void em_dev_unregister_perf_domain(struct device *dev);
190+
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd);
191+
void em_table_free(struct em_perf_table __rcu *table);
187192

188193
/**
189194
* em_pd_get_efficient_state() - Get an efficient performance state from the EM
@@ -365,6 +370,12 @@ static inline int em_pd_nr_perf_states(struct em_perf_domain *pd)
365370
{
366371
return 0;
367372
}
373+
static inline
374+
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
375+
{
376+
return NULL;
377+
}
378+
static inline void em_table_free(struct em_perf_table __rcu *table) {}
368379
#endif
369380

370381
#endif

kernel/power/energy_model.c

Lines changed: 33 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -114,20 +114,48 @@ static void em_destroy_table_rcu(struct rcu_head *rp)
114114
kfree(table);
115115
}
116116

117-
static void em_free_table(struct em_perf_table __rcu *table)
117+
static void em_release_table_kref(struct kref *kref)
118118
{
119+
struct em_perf_table __rcu *table;
120+
121+
/* It was the last owner of this table so we can free */
122+
table = container_of(kref, struct em_perf_table, kref);
123+
119124
call_rcu(&table->rcu, em_destroy_table_rcu);
120125
}
121126

122-
static struct em_perf_table __rcu *
123-
em_allocate_table(struct em_perf_domain *pd)
127+
/**
128+
* em_table_free() - Handles safe free of the EM table when needed
129+
* @table : EM table which is going to be freed
130+
*
131+
* No return values.
132+
*/
133+
void em_table_free(struct em_perf_table __rcu *table)
134+
{
135+
kref_put(&table->kref, em_release_table_kref);
136+
}
137+
138+
/**
139+
* em_table_alloc() - Allocate a new EM table
140+
* @pd : EM performance domain for which this must be done
141+
*
142+
* Allocate a new EM table and initialize its kref to indicate that it
143+
* has a user.
144+
* Returns allocated table or NULL.
145+
*/
146+
struct em_perf_table __rcu *em_table_alloc(struct em_perf_domain *pd)
124147
{
125148
struct em_perf_table __rcu *table;
126149
int table_size;
127150

128151
table_size = sizeof(struct em_perf_state) * pd->nr_perf_states;
129152

130153
table = kzalloc(sizeof(*table) + table_size, GFP_KERNEL);
154+
if (!table)
155+
return NULL;
156+
157+
kref_init(&table->kref);
158+
131159
return table;
132160
}
133161

@@ -186,7 +214,7 @@ static int em_create_runtime_table(struct em_perf_domain *pd)
186214
struct em_perf_table __rcu *table;
187215
int table_size;
188216

189-
table = em_allocate_table(pd);
217+
table = em_table_alloc(pd);
190218
if (!table)
191219
return -ENOMEM;
192220

@@ -512,7 +540,7 @@ void em_dev_unregister_perf_domain(struct device *dev)
512540

513541
kfree(dev->em_pd->table);
514542

515-
em_free_table(dev->em_pd->em_table);
543+
em_table_free(dev->em_pd->em_table);
516544

517545
kfree(dev->em_pd);
518546
dev->em_pd = NULL;

0 commit comments

Comments
 (0)