Skip to content

Commit 26984d9

Browse files
committed
PM / devfreq: passive: Keep cpufreq_policy for possible cpus
The passive governor requires the cpu data to get the next target frequency of devfreq device if depending on cpu. In order to reduce the unnecessary memory data, keep cpufreq_policy data for possible cpus instead of NR_CPU. Tested-by: Chen-Yu Tsai <wenst@chromium.org> Tested-by: Johnson Wang <johnson.wang@mediatek.com> Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
1 parent 05723e7 commit 26984d9

3 files changed

Lines changed: 64 additions & 18 deletions

File tree

drivers/devfreq/governor.h

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -49,6 +49,7 @@
4949

5050
/**
5151
* struct devfreq_cpu_data - Hold the per-cpu data
52+
* @node: list node
5253
* @dev: reference to cpu device.
5354
* @first_cpu: the cpumask of the first cpu of a policy.
5455
* @opp_table: reference to cpu opp table.
@@ -60,6 +61,8 @@
6061
* This is auto-populated by the governor.
6162
*/
6263
struct devfreq_cpu_data {
64+
struct list_head node;
65+
6366
struct device *dev;
6467
unsigned int first_cpu;
6568

drivers/devfreq/governor_passive.c

Lines changed: 59 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// SPDX-License-Identifier: GPL-2.0-only
1+
// SPDX-License-Identifier: GPL-2.0-only
22
/*
33
* linux/drivers/devfreq/governor_passive.c
44
*
@@ -18,6 +18,22 @@
1818

1919
#define HZ_PER_KHZ 1000
2020

21+
static struct devfreq_cpu_data *
22+
get_parent_cpu_data(struct devfreq_passive_data *p_data,
23+
struct cpufreq_policy *policy)
24+
{
25+
struct devfreq_cpu_data *parent_cpu_data;
26+
27+
if (!p_data || !policy)
28+
return NULL;
29+
30+
list_for_each_entry(parent_cpu_data, &p_data->cpu_data_list, node)
31+
if (parent_cpu_data->first_cpu == cpumask_first(policy->related_cpus))
32+
return parent_cpu_data;
33+
34+
return NULL;
35+
}
36+
2137
static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
2238
struct opp_table *p_opp_table,
2339
struct opp_table *opp_table,
@@ -51,14 +67,24 @@ static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
5167
struct devfreq_passive_data *p_data =
5268
(struct devfreq_passive_data *)devfreq->data;
5369
struct devfreq_cpu_data *parent_cpu_data;
70+
struct cpufreq_policy *policy;
5471
unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent;
5572
unsigned long dev_min, dev_max;
5673
unsigned long freq = 0;
74+
int ret = 0;
5775

5876
for_each_online_cpu(cpu) {
59-
parent_cpu_data = p_data->parent_cpu_data[cpu];
60-
if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu)
77+
policy = cpufreq_cpu_get(cpu);
78+
if (!policy) {
79+
ret = -EINVAL;
80+
continue;
81+
}
82+
83+
parent_cpu_data = get_parent_cpu_data(p_data, policy);
84+
if (!parent_cpu_data) {
85+
cpufreq_cpu_put(policy);
6186
continue;
87+
}
6288

6389
/* Get target freq via required opps */
6490
cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ;
@@ -67,6 +93,7 @@ static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
6793
devfreq->opp_table, &cpu_cur);
6894
if (freq) {
6995
*target_freq = max(freq, *target_freq);
96+
cpufreq_cpu_put(policy);
7097
continue;
7198
}
7299

@@ -81,9 +108,10 @@ static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
81108
freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100);
82109

83110
*target_freq = max(freq, *target_freq);
111+
cpufreq_cpu_put(policy);
84112
}
85113

86-
return 0;
114+
return ret;
87115
}
88116

89117
static int get_target_freq_with_devfreq(struct devfreq *devfreq,
@@ -168,12 +196,11 @@ static int cpufreq_passive_notifier_call(struct notifier_block *nb,
168196
unsigned int cur_freq;
169197
int ret;
170198

171-
if (event != CPUFREQ_POSTCHANGE || !freqs ||
172-
!p_data->parent_cpu_data[freqs->policy->cpu])
199+
if (event != CPUFREQ_POSTCHANGE || !freqs)
173200
return 0;
174201

175-
parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu];
176-
if (parent_cpu_data->cur_freq == freqs->new)
202+
parent_cpu_data = get_parent_cpu_data(p_data, freqs->policy);
203+
if (!parent_cpu_data || parent_cpu_data->cur_freq == freqs->new)
177204
return 0;
178205

179206
cur_freq = parent_cpu_data->cur_freq;
@@ -196,7 +223,7 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
196223
struct devfreq_passive_data *p_data
197224
= (struct devfreq_passive_data *)devfreq->data;
198225
struct devfreq_cpu_data *parent_cpu_data;
199-
int cpu, ret;
226+
int cpu, ret = 0;
200227

201228
if (p_data->nb.notifier_call) {
202229
ret = cpufreq_unregister_notifier(&p_data->nb,
@@ -206,16 +233,26 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
206233
}
207234

208235
for_each_possible_cpu(cpu) {
209-
parent_cpu_data = p_data->parent_cpu_data[cpu];
210-
if (!parent_cpu_data)
236+
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
237+
if (!policy) {
238+
ret = -EINVAL;
211239
continue;
240+
}
212241

242+
parent_cpu_data = get_parent_cpu_data(p_data, policy);
243+
if (!parent_cpu_data) {
244+
cpufreq_cpu_put(policy);
245+
continue;
246+
}
247+
248+
list_del(&parent_cpu_data->node);
213249
if (parent_cpu_data->opp_table)
214250
dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
215251
kfree(parent_cpu_data);
252+
cpufreq_cpu_put(policy);
216253
}
217254

218-
return 0;
255+
return ret;
219256
}
220257

221258
static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
@@ -230,6 +267,9 @@ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
230267
unsigned int cpu;
231268
int ret;
232269

270+
p_data->cpu_data_list
271+
= (struct list_head)LIST_HEAD_INIT(p_data->cpu_data_list);
272+
233273
p_data->nb.notifier_call = cpufreq_passive_notifier_call;
234274
ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER);
235275
if (ret) {
@@ -239,15 +279,18 @@ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
239279
}
240280

241281
for_each_possible_cpu(cpu) {
242-
if (p_data->parent_cpu_data[cpu])
243-
continue;
244-
245282
policy = cpufreq_cpu_get(cpu);
246283
if (!policy) {
247284
ret = -EPROBE_DEFER;
248285
goto err;
249286
}
250287

288+
parent_cpu_data = get_parent_cpu_data(p_data, policy);
289+
if (parent_cpu_data) {
290+
cpufreq_cpu_put(policy);
291+
continue;
292+
}
293+
251294
parent_cpu_data = kzalloc(sizeof(*parent_cpu_data),
252295
GFP_KERNEL);
253296
if (!parent_cpu_data) {
@@ -276,7 +319,7 @@ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
276319
parent_cpu_data->min_freq = policy->cpuinfo.min_freq;
277320
parent_cpu_data->max_freq = policy->cpuinfo.max_freq;
278321

279-
p_data->parent_cpu_data[cpu] = parent_cpu_data;
322+
list_add_tail(&parent_cpu_data->node, &p_data->cpu_data_list);
280323
cpufreq_cpu_put(policy);
281324
}
282325

include/linux/devfreq.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ enum devfreq_parent_dev_type {
309309
* @this: the devfreq instance of own device.
310310
* @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or
311311
* CPUFREQ_TRANSITION_NOTIFIER list.
312-
* @parent_cpu_data: the state min/max/current frequency of all online cpu's.
312+
* @cpu_data_list: the list of cpu frequency data for all cpufreq_policy.
313313
*
314314
* The devfreq_passive_data have to set the devfreq instance of parent
315315
* device with governors except for the passive governor. But, don't need to
@@ -329,7 +329,7 @@ struct devfreq_passive_data {
329329
/* For passive governor's internal use. Don't need to set them */
330330
struct devfreq *this;
331331
struct notifier_block nb;
332-
struct devfreq_cpu_data *parent_cpu_data[NR_CPUS];
332+
struct list_head cpu_data_list;
333333
};
334334
#endif
335335

0 commit comments

Comments
 (0)