Skip to content

Commit 589cb2c

Browse files
committed
Merge tag 'devfreq-fixes-for-5.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux
Pull devfreq fixes for 5.19-rc5 from Chanwoo Choi: "1. Fix devfreq passive governor issue when cpufreq policies are not ready during kernel boot because some CPUs turn on after kernel booting or others. - Re-initialize the vairables of struct devfreq_passive_data when PROBE_DEFER happens when cpufreq_get() returns NULL. - Use dev_err_probe to mute warning when PROBE_DEFER. - Fix cpufreq passive unregister erroring on PROBE_DEFER by using the allocated parent_cpu_data list to free resouce instead of for_each_possible_cpu(). - Remove duplicate cpufreq passive unregister and warning when PROBE_DEFER. - Use HZ_PER_KZH macro in units.h. - Fix wrong indentation in SPDX-License line. 2. Fix reference count leak in exynos-ppmu.c by using of_node_put(). 3. Rework freq_table to be local to devfreq struct - struct devfreq_dev_profile includes freq_table array to store the supported frequencies. If devfreq driver doesn't initialize the freq_table, devfreq core allocates the memory and initializes the freq_table. On a devfreq PROBE_DEFER, the freq_table in the driver profile struct is never reset and may be left in an undefined state. To fix this and correctly handle PROBE_DEFER, use a local freq_table and max_state in the devfreq struct." * tag 'devfreq-fixes-for-5.19-rc5' of git://git.kernel.org/pub/scm/linux/kernel/git/chanwoo/linux: PM / devfreq: passive: revert an editing accident in SPDX-License line PM / devfreq: Fix kernel warning with cpufreq passive register fail PM / devfreq: Rework freq_table to be local to devfreq struct PM / devfreq: exynos-ppmu: Fix refcount leak in of_get_devfreq_events PM / devfreq: passive: Use HZ_PER_KHZ macro in units.h PM / devfreq: Fix cpufreq passive unregister erroring on PROBE_DEFER PM / devfreq: Mute warning on governor PROBE_DEFER PM / devfreq: Fix kernel panic with cpu based scaling to passive gov
2 parents 03c765b + f08fe6f commit 589cb2c

File tree

4 files changed

+75
-76
lines changed

4 files changed

+75
-76
lines changed

drivers/devfreq/devfreq.c

Lines changed: 37 additions & 39 deletions
Original file line numberDiff line numberDiff line change
@@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
123123
unsigned long *min_freq,
124124
unsigned long *max_freq)
125125
{
126-
unsigned long *freq_table = devfreq->profile->freq_table;
126+
unsigned long *freq_table = devfreq->freq_table;
127127
s32 qos_min_freq, qos_max_freq;
128128

129129
lockdep_assert_held(&devfreq->lock);
@@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfreq *devfreq,
133133
* The devfreq drivers can initialize this in either ascending or
134134
* descending order and devfreq core supports both.
135135
*/
136-
if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
136+
if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
137137
*min_freq = freq_table[0];
138-
*max_freq = freq_table[devfreq->profile->max_state - 1];
138+
*max_freq = freq_table[devfreq->max_state - 1];
139139
} else {
140-
*min_freq = freq_table[devfreq->profile->max_state - 1];
140+
*min_freq = freq_table[devfreq->max_state - 1];
141141
*max_freq = freq_table[0];
142142
}
143143

@@ -169,16 +169,15 @@ static int devfreq_get_freq_level(struct devfreq *devfreq, unsigned long freq)
169169
{
170170
int lev;
171171

172-
for (lev = 0; lev < devfreq->profile->max_state; lev++)
173-
if (freq == devfreq->profile->freq_table[lev])
172+
for (lev = 0; lev < devfreq->max_state; lev++)
173+
if (freq == devfreq->freq_table[lev])
174174
return lev;
175175

176176
return -EINVAL;
177177
}
178178

179179
static int set_freq_table(struct devfreq *devfreq)
180180
{
181-
struct devfreq_dev_profile *profile = devfreq->profile;
182181
struct dev_pm_opp *opp;
183182
unsigned long freq;
184183
int i, count;
@@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq *devfreq)
188187
if (count <= 0)
189188
return -EINVAL;
190189

191-
profile->max_state = count;
192-
profile->freq_table = devm_kcalloc(devfreq->dev.parent,
193-
profile->max_state,
194-
sizeof(*profile->freq_table),
195-
GFP_KERNEL);
196-
if (!profile->freq_table) {
197-
profile->max_state = 0;
190+
devfreq->max_state = count;
191+
devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
192+
devfreq->max_state,
193+
sizeof(*devfreq->freq_table),
194+
GFP_KERNEL);
195+
if (!devfreq->freq_table)
198196
return -ENOMEM;
199-
}
200197

201-
for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
198+
for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
202199
opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
203200
if (IS_ERR(opp)) {
204-
devm_kfree(devfreq->dev.parent, profile->freq_table);
205-
profile->max_state = 0;
201+
devm_kfree(devfreq->dev.parent, devfreq->freq_table);
206202
return PTR_ERR(opp);
207203
}
208204
dev_pm_opp_put(opp);
209-
profile->freq_table[i] = freq;
205+
devfreq->freq_table[i] = freq;
210206
}
211207

212208
return 0;
@@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq)
246242

247243
if (lev != prev_lev) {
248244
devfreq->stats.trans_table[
249-
(prev_lev * devfreq->profile->max_state) + lev]++;
245+
(prev_lev * devfreq->max_state) + lev]++;
250246
devfreq->stats.total_trans++;
251247
}
252248

@@ -835,6 +831,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
835831
if (err < 0)
836832
goto err_dev;
837833
mutex_lock(&devfreq->lock);
834+
} else {
835+
devfreq->freq_table = devfreq->profile->freq_table;
836+
devfreq->max_state = devfreq->profile->max_state;
838837
}
839838

840839
devfreq->scaling_min_freq = find_available_min_freq(devfreq);
@@ -870,8 +869,8 @@ struct devfreq *devfreq_add_device(struct device *dev,
870869

871870
devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
872871
array3_size(sizeof(unsigned int),
873-
devfreq->profile->max_state,
874-
devfreq->profile->max_state),
872+
devfreq->max_state,
873+
devfreq->max_state),
875874
GFP_KERNEL);
876875
if (!devfreq->stats.trans_table) {
877876
mutex_unlock(&devfreq->lock);
@@ -880,7 +879,7 @@ struct devfreq *devfreq_add_device(struct device *dev,
880879
}
881880

882881
devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
883-
devfreq->profile->max_state,
882+
devfreq->max_state,
884883
sizeof(*devfreq->stats.time_in_state),
885884
GFP_KERNEL);
886885
if (!devfreq->stats.time_in_state) {
@@ -932,8 +931,9 @@ struct devfreq *devfreq_add_device(struct device *dev,
932931
err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
933932
NULL);
934933
if (err) {
935-
dev_err(dev, "%s: Unable to start governor for the device\n",
936-
__func__);
934+
dev_err_probe(dev, err,
935+
"%s: Unable to start governor for the device\n",
936+
__func__);
937937
goto err_init;
938938
}
939939
create_sysfs_files(devfreq, devfreq->governor);
@@ -1665,9 +1665,9 @@ static ssize_t available_frequencies_show(struct device *d,
16651665

16661666
mutex_lock(&df->lock);
16671667

1668-
for (i = 0; i < df->profile->max_state; i++)
1668+
for (i = 0; i < df->max_state; i++)
16691669
count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
1670-
"%lu ", df->profile->freq_table[i]);
1670+
"%lu ", df->freq_table[i]);
16711671

16721672
mutex_unlock(&df->lock);
16731673
/* Truncate the trailing space */
@@ -1690,7 +1690,7 @@ static ssize_t trans_stat_show(struct device *dev,
16901690

16911691
if (!df->profile)
16921692
return -EINVAL;
1693-
max_state = df->profile->max_state;
1693+
max_state = df->max_state;
16941694

16951695
if (max_state == 0)
16961696
return sprintf(buf, "Not Supported.\n");
@@ -1707,19 +1707,17 @@ static ssize_t trans_stat_show(struct device *dev,
17071707
len += sprintf(buf + len, " :");
17081708
for (i = 0; i < max_state; i++)
17091709
len += sprintf(buf + len, "%10lu",
1710-
df->profile->freq_table[i]);
1710+
df->freq_table[i]);
17111711

17121712
len += sprintf(buf + len, " time(ms)\n");
17131713

17141714
for (i = 0; i < max_state; i++) {
1715-
if (df->profile->freq_table[i]
1716-
== df->previous_freq) {
1715+
if (df->freq_table[i] == df->previous_freq)
17171716
len += sprintf(buf + len, "*");
1718-
} else {
1717+
else
17191718
len += sprintf(buf + len, " ");
1720-
}
1721-
len += sprintf(buf + len, "%10lu:",
1722-
df->profile->freq_table[i]);
1719+
1720+
len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
17231721
for (j = 0; j < max_state; j++)
17241722
len += sprintf(buf + len, "%10u",
17251723
df->stats.trans_table[(i * max_state) + j]);
@@ -1743,19 +1741,19 @@ static ssize_t trans_stat_store(struct device *dev,
17431741
if (!df->profile)
17441742
return -EINVAL;
17451743

1746-
if (df->profile->max_state == 0)
1744+
if (df->max_state == 0)
17471745
return count;
17481746

17491747
err = kstrtoint(buf, 10, &value);
17501748
if (err || value != 0)
17511749
return -EINVAL;
17521750

17531751
mutex_lock(&df->lock);
1754-
memset(df->stats.time_in_state, 0, (df->profile->max_state *
1752+
memset(df->stats.time_in_state, 0, (df->max_state *
17551753
sizeof(*df->stats.time_in_state)));
17561754
memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
1757-
df->profile->max_state,
1758-
df->profile->max_state));
1755+
df->max_state,
1756+
df->max_state));
17591757
df->stats.total_trans = 0;
17601758
df->stats.last_update = get_jiffies_64();
17611759
mutex_unlock(&df->lock);

drivers/devfreq/event/exynos-ppmu.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -519,15 +519,19 @@ static int of_get_devfreq_events(struct device_node *np,
519519

520520
count = of_get_child_count(events_np);
521521
desc = devm_kcalloc(dev, count, sizeof(*desc), GFP_KERNEL);
522-
if (!desc)
522+
if (!desc) {
523+
of_node_put(events_np);
523524
return -ENOMEM;
525+
}
524526
info->num_events = count;
525527

526528
of_id = of_match_device(exynos_ppmu_id_match, dev);
527529
if (of_id)
528530
info->ppmu_type = (enum exynos_ppmu_type)of_id->data;
529-
else
531+
else {
532+
of_node_put(events_np);
530533
return -EINVAL;
534+
}
531535

532536
j = 0;
533537
for_each_child_of_node(events_np, node) {

drivers/devfreq/governor_passive.c

Lines changed: 27 additions & 35 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
*
@@ -14,10 +14,9 @@
1414
#include <linux/slab.h>
1515
#include <linux/device.h>
1616
#include <linux/devfreq.h>
17+
#include <linux/units.h>
1718
#include "governor.h"
1819

19-
#define HZ_PER_KHZ 1000
20-
2120
static struct devfreq_cpu_data *
2221
get_parent_cpu_data(struct devfreq_passive_data *p_data,
2322
struct cpufreq_policy *policy)
@@ -34,6 +33,20 @@ get_parent_cpu_data(struct devfreq_passive_data *p_data,
3433
return NULL;
3534
}
3635

36+
static void delete_parent_cpu_data(struct devfreq_passive_data *p_data)
37+
{
38+
struct devfreq_cpu_data *parent_cpu_data, *tmp;
39+
40+
list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) {
41+
list_del(&parent_cpu_data->node);
42+
43+
if (parent_cpu_data->opp_table)
44+
dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
45+
46+
kfree(parent_cpu_data);
47+
}
48+
}
49+
3750
static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
3851
struct opp_table *p_opp_table,
3952
struct opp_table *opp_table,
@@ -131,18 +144,18 @@ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
131144
goto out;
132145

133146
/* Use interpolation if required opps is not available */
134-
for (i = 0; i < parent_devfreq->profile->max_state; i++)
135-
if (parent_devfreq->profile->freq_table[i] == *freq)
147+
for (i = 0; i < parent_devfreq->max_state; i++)
148+
if (parent_devfreq->freq_table[i] == *freq)
136149
break;
137150

138-
if (i == parent_devfreq->profile->max_state)
151+
if (i == parent_devfreq->max_state)
139152
return -EINVAL;
140153

141-
if (i < devfreq->profile->max_state) {
142-
child_freq = devfreq->profile->freq_table[i];
154+
if (i < devfreq->max_state) {
155+
child_freq = devfreq->freq_table[i];
143156
} else {
144-
count = devfreq->profile->max_state;
145-
child_freq = devfreq->profile->freq_table[count - 1];
157+
count = devfreq->max_state;
158+
child_freq = devfreq->freq_table[count - 1];
146159
}
147160

148161
out:
@@ -222,8 +235,7 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
222235
{
223236
struct devfreq_passive_data *p_data
224237
= (struct devfreq_passive_data *)devfreq->data;
225-
struct devfreq_cpu_data *parent_cpu_data;
226-
int cpu, ret = 0;
238+
int ret;
227239

228240
if (p_data->nb.notifier_call) {
229241
ret = cpufreq_unregister_notifier(&p_data->nb,
@@ -232,27 +244,9 @@ static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
232244
return ret;
233245
}
234246

235-
for_each_possible_cpu(cpu) {
236-
struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
237-
if (!policy) {
238-
ret = -EINVAL;
239-
continue;
240-
}
241-
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+
delete_parent_cpu_data(p_data);
247248

248-
list_del(&parent_cpu_data->node);
249-
if (parent_cpu_data->opp_table)
250-
dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
251-
kfree(parent_cpu_data);
252-
cpufreq_cpu_put(policy);
253-
}
254-
255-
return ret;
249+
return 0;
256250
}
257251

258252
static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
@@ -336,7 +330,6 @@ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
336330
err_put_policy:
337331
cpufreq_cpu_put(policy);
338332
err:
339-
WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
340333

341334
return ret;
342335
}
@@ -407,8 +400,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
407400
if (!p_data)
408401
return -EINVAL;
409402

410-
if (!p_data->this)
411-
p_data->this = devfreq;
403+
p_data->this = devfreq;
412404

413405
switch (event) {
414406
case DEVFREQ_GOV_START:

include/linux/devfreq.h

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -148,6 +148,8 @@ struct devfreq_stats {
148148
* reevaluate operable frequencies. Devfreq users may use
149149
* devfreq.nb to the corresponding register notifier call chain.
150150
* @work: delayed work for load monitoring.
151+
* @freq_table: current frequency table used by the devfreq driver.
152+
* @max_state: count of entry present in the frequency table.
151153
* @previous_freq: previously configured frequency value.
152154
* @last_status: devfreq user device info, performance statistics
153155
* @data: Private data of the governor. The devfreq framework does not
@@ -185,6 +187,9 @@ struct devfreq {
185187
struct notifier_block nb;
186188
struct delayed_work work;
187189

190+
unsigned long *freq_table;
191+
unsigned int max_state;
192+
188193
unsigned long previous_freq;
189194
struct devfreq_dev_status last_status;
190195

0 commit comments

Comments
 (0)