ipq806x: 6.1: copy patches, files and config from 5.15
[openwrt/staging/ldir.git] / target / linux / ipq806x / patches-6.1 / 113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch
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
5 struct
6
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
12 required.
13
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.
19
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.
23
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
30 by the driver.
31
32 Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
33 Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
34 ---
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(-)
39
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)
45 {
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;
49
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.
54 */
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];
60 } else {
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];
64 }
65
66 @@ -169,8 +169,8 @@ static int devfreq_get_freq_level(struct
67 {
68 int lev;
69
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])
74 return lev;
75
76 return -EINVAL;
77 @@ -178,7 +178,6 @@ static int devfreq_get_freq_level(struct
78
79 static int set_freq_table(struct devfreq *devfreq)
80 {
81 - struct devfreq_dev_profile *profile = devfreq->profile;
82 struct dev_pm_opp *opp;
83 unsigned long freq;
84 int i, count;
85 @@ -188,25 +187,22 @@ static int set_freq_table(struct devfreq
86 if (count <= 0)
87 return -EINVAL;
88
89 - profile->max_state = count;
90 - profile->freq_table = devm_kcalloc(devfreq->dev.parent,
91 - profile->max_state,
92 - sizeof(*profile->freq_table),
93 - GFP_KERNEL);
94 - if (!profile->freq_table) {
95 - profile->max_state = 0;
96 + devfreq->max_state = count;
97 + devfreq->freq_table = devm_kcalloc(devfreq->dev.parent,
98 + devfreq->max_state,
99 + sizeof(*devfreq->freq_table),
100 + GFP_KERNEL);
101 + if (!devfreq->freq_table)
102 return -ENOMEM;
103 - }
104
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);
108 if (IS_ERR(opp)) {
109 - devm_kfree(devfreq->dev.parent, profile->freq_table);
110 - profile->max_state = 0;
111 + devm_kfree(devfreq->dev.parent, devfreq->freq_table);
112 return PTR_ERR(opp);
113 }
114 dev_pm_opp_put(opp);
115 - profile->freq_table[i] = freq;
116 + devfreq->freq_table[i] = freq;
117 }
118
119 return 0;
120 @@ -246,7 +242,7 @@ int devfreq_update_status(struct devfreq
121
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++;
127 }
128
129 @@ -834,6 +830,9 @@ struct devfreq *devfreq_add_device(struc
130 if (err < 0)
131 goto err_dev;
132 mutex_lock(&devfreq->lock);
133 + } else {
134 + devfreq->freq_table = devfreq->profile->freq_table;
135 + devfreq->max_state = devfreq->profile->max_state;
136 }
137
138 devfreq->scaling_min_freq = find_available_min_freq(devfreq);
139 @@ -869,8 +868,8 @@ struct devfreq *devfreq_add_device(struc
140
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),
147 GFP_KERNEL);
148 if (!devfreq->stats.trans_table) {
149 mutex_unlock(&devfreq->lock);
150 @@ -879,7 +878,7 @@ struct devfreq *devfreq_add_device(struc
151 }
152
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),
157 GFP_KERNEL);
158 if (!devfreq->stats.time_in_state) {
159 @@ -1637,9 +1636,9 @@ static ssize_t available_frequencies_sho
160
161 mutex_lock(&df->lock);
162
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]);
168
169 mutex_unlock(&df->lock);
170 /* Truncate the trailing space */
171 @@ -1662,7 +1661,7 @@ static ssize_t trans_stat_show(struct de
172
173 if (!df->profile)
174 return -EINVAL;
175 - max_state = df->profile->max_state;
176 + max_state = df->max_state;
177
178 if (max_state == 0)
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]);
186
187 len += sprintf(buf + len, " time(ms)\n");
188
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, "*");
194 - } else {
195 + else
196 len += sprintf(buf + len, " ");
197 - }
198 - len += sprintf(buf + len, "%10lu:",
199 - df->profile->freq_table[i]);
200 +
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
206 if (!df->profile)
207 return -EINVAL;
208
209 - if (df->profile->max_state == 0)
210 + if (df->max_state == 0)
211 return count;
212
213 err = kstrtoint(buf, 10, &value);
214 @@ -1723,11 +1720,11 @@ static ssize_t trans_stat_store(struct d
215 return -EINVAL;
216
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));
224 + df->max_state,
225 + df->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(
232 goto out;
233
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)
239 break;
240
241 - if (i == parent_devfreq->profile->max_state)
242 + if (i == parent_devfreq->max_state)
243 return -EINVAL;
244
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];
249 } else {
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];
254 }
255
256 out:
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;
262
263 + /* devfreq local freq_table */
264 + unsigned long *freq_table;
265 + unsigned int max_state;
266 +
267 unsigned long previous_freq;
268 struct devfreq_dev_status last_status;
269