1 From 46d05776a1a5dd8eb479e868f5ff4f4b97d68238 Mon Sep 17 00:00:00 2001
2 From: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
3 Date: Mon, 6 Jun 2022 12:39:19 +0200
4 Subject: [PATCH v4 3/4] PM / devfreq: Rework freq_table to be local to devfreq
7 Currently we reference the freq_table to the profile defined one and we
8 make changes on it. Devfreq never supported PROBE_DEFER before the cpu
9 based scaling support to the passive governor and assumed that a devfreq
10 device could only had error and be done with it.
11 Now that a device can PROBE_DEFER a rework to the freq_table logic is
14 If a device PROBE_DEFER on the GOV_START, the freq_table is already set
15 in the device profile struct and its init is skipped. This is due to the
16 fact that it's common for devs to declare this kind of struct static.
17 This cause the devfreq logic to find a freq table declared (freq_table
18 not NULL) with random data and poiting to the old addrs freed by devm.
20 This problem CAN be solved by devs by clearing the freq_table in their
21 profile struct on driver exit path but it should not be trusted and it
22 looks to use a flawed logic.
24 A better solution is to move the freq_table and max_state to the
25 devfreq struct and never change the profile struct.
26 This permit to correctly handle PROBE_DEFER since the devfreq struct is
27 reallocated and contains new values.
28 Also the profile struct should only be used to init the driver and should
29 not be used by the devfreq to write the freq_table if it's not provided
32 Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
33 Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
35 drivers/devfreq/devfreq.c | 71 ++++++++++++++----------------
36 drivers/devfreq/governor_passive.c | 14 +++---
37 include/linux/devfreq.h | 4 ++
38 3 files changed, 45 insertions(+), 44 deletions(-)
40 --- a/drivers/devfreq/devfreq.c
41 +++ b/drivers/devfreq/devfreq.c
42 @@ -123,7 +123,7 @@ void devfreq_get_freq_range(struct devfr
43 unsigned long *min_freq,
44 unsigned long *max_freq)
46 - unsigned long *freq_table = devfreq->profile->freq_table;
47 + unsigned long *freq_table = devfreq->freq_table;
48 s32 qos_min_freq, qos_max_freq;
50 lockdep_assert_held(&devfreq->lock);
51 @@ -133,11 +133,11 @@ void devfreq_get_freq_range(struct devfr
52 * The devfreq drivers can initialize this in either ascending or
53 * descending order and devfreq core supports both.
55 - if (freq_table[0] < freq_table[devfreq->profile->max_state - 1]) {
56 + if (freq_table[0] < freq_table[devfreq->max_state - 1]) {
57 *min_freq = freq_table[0];
58 - *max_freq = freq_table[devfreq->profile->max_state - 1];
59 + *max_freq = freq_table[devfreq->max_state - 1];
61 - *min_freq = freq_table[devfreq->profile->max_state - 1];
62 + *min_freq = freq_table[devfreq->max_state - 1];
63 *max_freq = freq_table[0];
66 @@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct
70 - for (lev = 0; lev < devfreq->profile->max_state; lev++)
71 - if (freq == devfreq->profile->freq_table[lev])
72 + for (lev = 0; lev < devfreq->max_state; lev++)
73 + if (freq == devfreq->freq_table[lev])
77 @@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct
79 static int set_freq_table(struct devfreq *devfreq)
81 - struct devfreq_dev_profile *profile = devfreq->profile;
82 struct dev_pm_opp *opp;
85 @@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq
89 - profile->max_state = count;
90 - profile->freq_table = devm_kcalloc(devfreq->dev.parent,
92 - sizeof(*profile->freq_table),
94 - if (!profile->freq_table) {
95 - profile->max_state = 0;
96 + devfreq->max_state = count;
97 + devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
99 + sizeof(*devfreq->freq_table),
101 + if (!devfreq->freq_table)
105 - for (i = 0, freq = 0; i < profile->max_state; i++, freq++) {
106 + for (i = 0, freq = 0; i < devfreq->max_state; i++, freq++) {
107 opp = dev_pm_opp_find_freq_ceil(devfreq->dev.parent, &freq);
109 - devm_kfree(devfreq->dev.parent, profile->freq_table);
110 - profile->max_state = 0;
111 + devm_kfree(devfreq->dev.parent, devfreq->freq_table);
115 - profile->freq_table[i] = freq;
116 + devfreq->freq_table[i] = freq;
120 @@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq
122 if (lev != prev_lev) {
123 devfreq->stats.trans_table[
124 - (prev_lev * devfreq->profile->max_state) + lev]++;
125 + (prev_lev * devfreq->max_state) + lev]++;
126 devfreq->stats.total_trans++;
129 @@ -834,6 +830,9 @@ struct devfreq *devfreq_add_device(struc
132 mutex_lock(&devfreq->lock);
134 + devfreq->freq_table = devfreq->profile->freq_table;
135 + devfreq->max_state = devfreq->profile->max_state;
138 devfreq->scaling_min_freq = find_available_min_freq(devfreq);
139 @@ -869,8 +868,8 @@ struct devfreq *devfreq_add_device(struc
141 devfreq->stats.trans_table = devm_kzalloc(&devfreq->dev,
142 array3_size(sizeof(unsigned int),
143 - devfreq->profile->max_state,
144 - devfreq->profile->max_state),
145 + devfreq->max_state,
146 + devfreq->max_state),
148 if (!devfreq->stats.trans_table) {
149 mutex_unlock(&devfreq->lock);
150 @@ -879,7 +878,7 @@ struct devfreq *devfreq_add_device(struc
153 devfreq->stats.time_in_state = devm_kcalloc(&devfreq->dev,
154 - devfreq->profile->max_state,
155 + devfreq->max_state,
156 sizeof(*devfreq->stats.time_in_state),
158 if (!devfreq->stats.time_in_state) {
159 @@ -1637,9 +1636,9 @@ static ssize_t available_frequencies_sho
161 mutex_lock(&df->lock);
163 - for (i = 0; i < df->profile->max_state; i++)
164 + for (i = 0; i < df->max_state; i++)
165 count += scnprintf(&buf[count], (PAGE_SIZE - count - 2),
166 - "%lu ", df->profile->freq_table[i]);
167 + "%lu ", df->freq_table[i]);
169 mutex_unlock(&df->lock);
170 /* Truncate the trailing space */
171 @@ -1662,7 +1661,7 @@ static ssize_t trans_stat_show(struct de
175 - max_state = df->profile->max_state;
176 + max_state = df->max_state;
179 return sprintf(buf, "Not Supported.\n");
180 @@ -1679,19 +1678,17 @@ static ssize_t trans_stat_show(struct de
181 len += sprintf(buf + len, " :");
182 for (i = 0; i < max_state; i++)
183 len += sprintf(buf + len, "%10lu",
184 - df->profile->freq_table[i]);
185 + df->freq_table[i]);
187 len += sprintf(buf + len, " time(ms)\n");
189 for (i = 0; i < max_state; i++) {
190 - if (df->profile->freq_table[i]
191 - == df->previous_freq) {
192 + if (df->freq_table[i] == df->previous_freq)
193 len += sprintf(buf + len, "*");
196 len += sprintf(buf + len, " ");
198 - len += sprintf(buf + len, "%10lu:",
199 - df->profile->freq_table[i]);
201 + len += sprintf(buf + len, "%10lu:", df->freq_table[i]);
202 for (j = 0; j < max_state; j++)
203 len += sprintf(buf + len, "%10u",
204 df->stats.trans_table[(i * max_state) + j]);
205 @@ -1715,7 +1712,7 @@ static ssize_t trans_stat_store(struct d
209 - if (df->profile->max_state == 0)
210 + if (df->max_state == 0)
213 err = kstrtoint(buf, 10, &value);
214 @@ -1723,11 +1720,11 @@ static ssize_t trans_stat_store(struct d
217 mutex_lock(&df->lock);
218 - memset(df->stats.time_in_state, 0, (df->profile->max_state *
219 + memset(df->stats.time_in_state, 0, (df->max_state *
220 sizeof(*df->stats.time_in_state)));
221 memset(df->stats.trans_table, 0, array3_size(sizeof(unsigned int),
222 - df->profile->max_state,
223 - df->profile->max_state));
226 df->stats.total_trans = 0;
227 df->stats.last_update = get_jiffies_64();
228 mutex_unlock(&df->lock);
229 --- a/drivers/devfreq/governor_passive.c
230 +++ b/drivers/devfreq/governor_passive.c
231 @@ -145,18 +145,18 @@ static int get_target_freq_with_devfreq(
234 /* Use interpolation if required opps is not available */
235 - for (i = 0; i < parent_devfreq->profile->max_state; i++)
236 - if (parent_devfreq->profile->freq_table[i] == *freq)
237 + for (i = 0; i < parent_devfreq->max_state; i++)
238 + if (parent_devfreq->freq_table[i] == *freq)
241 - if (i == parent_devfreq->profile->max_state)
242 + if (i == parent_devfreq->max_state)
245 - if (i < devfreq->profile->max_state) {
246 - child_freq = devfreq->profile->freq_table[i];
247 + if (i < devfreq->max_state) {
248 + child_freq = devfreq->freq_table[i];
250 - count = devfreq->profile->max_state;
251 - child_freq = devfreq->profile->freq_table[count - 1];
252 + count = devfreq->max_state;
253 + child_freq = devfreq->freq_table[count - 1];
257 --- a/include/linux/devfreq.h
258 +++ b/include/linux/devfreq.h
259 @@ -185,6 +185,10 @@ struct devfreq {
260 struct notifier_block nb;
261 struct delayed_work work;
263 + /* devfreq local freq_table */
264 + unsigned long *freq_table;
265 + unsigned int max_state;
267 unsigned long previous_freq;
268 struct devfreq_dev_status last_status;