• R/O
  • HTTP
  • SSH
  • HTTPS

提交

Frequently used words (click to add to your profile)

javac++androidlinuxc#windowsobjective-ccocoa誰得qtpythonphprubygameguibathyscaphec計画中(planning stage)翻訳omegatframeworktwitterdomtestvb.netdirectxゲームエンジンbtronarduinopreviewer

Mirror only - Please move to https://github.com/immortalwrt/immortalwrt


Commit MetaInfo

修订版3a911b8c2d97293f04288775599843ab5cb77045 (tree)
时间2022-10-12 04:28:42
作者Christian Marangi <ansuelsmth@gmai...>
CommiterChristian Marangi

Log Message

ipq806x: 5.15: backport devfreq new cpufreq based PASSIVE governor

Backport devfreq new cpufreq based PASSIVE governor needed for devfreq
based fab and cache scaling.

Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>

更改概述

差异

--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/111-v5.19-01-PM-devfreq-Export-devfreq_get_freq_range-symbol-with.patch
@@ -0,0 +1,113 @@
1+From 713472e53e6e53c985e283782b0fd76b8ecfd47e Mon Sep 17 00:00:00 2001
2+From: Chanwoo Choi <cw00.choi@samsung.com>
3+Date: Mon, 1 Mar 2021 02:07:29 +0900
4+Subject: [PATCH 1/5] PM / devfreq: Export devfreq_get_freq_range symbol within
5+ devfreq
6+
7+In order to get frequency range within devfreq governors,
8+export devfreq_get_freq_range symbol within devfreq.
9+
10+Reviewed-by: Matthias Kaehlcke <mka@chromium.org>
11+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
12+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
13+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
14+---
15+ drivers/devfreq/devfreq.c | 20 ++++++++++++--------
16+ drivers/devfreq/governor.h | 2 ++
17+ 2 files changed, 14 insertions(+), 8 deletions(-)
18+
19+--- a/drivers/devfreq/devfreq.c
20++++ b/drivers/devfreq/devfreq.c
21+@@ -112,16 +112,16 @@ static unsigned long find_available_max_
22+ }
23+
24+ /**
25+- * get_freq_range() - Get the current freq range
26++ * devfreq_get_freq_range() - Get the current freq range
27+ * @devfreq: the devfreq instance
28+ * @min_freq: the min frequency
29+ * @max_freq: the max frequency
30+ *
31+ * This takes into consideration all constraints.
32+ */
33+-static void get_freq_range(struct devfreq *devfreq,
34+- unsigned long *min_freq,
35+- unsigned long *max_freq)
36++void devfreq_get_freq_range(struct devfreq *devfreq,
37++ unsigned long *min_freq,
38++ unsigned long *max_freq)
39+ {
40+ unsigned long *freq_table = devfreq->profile->freq_table;
41+ s32 qos_min_freq, qos_max_freq;
42+@@ -158,6 +158,7 @@ static void get_freq_range(struct devfre
43+ if (*min_freq > *max_freq)
44+ *min_freq = *max_freq;
45+ }
46++EXPORT_SYMBOL(devfreq_get_freq_range);
47+
48+ /**
49+ * devfreq_get_freq_level() - Lookup freq_table for the frequency
50+@@ -418,7 +419,7 @@ int devfreq_update_target(struct devfreq
51+ err = devfreq->governor->get_target_freq(devfreq, &freq);
52+ if (err)
53+ return err;
54+- get_freq_range(devfreq, &min_freq, &max_freq);
55++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
56+
57+ if (freq < min_freq) {
58+ freq = min_freq;
59+@@ -785,6 +786,7 @@ struct devfreq *devfreq_add_device(struc
60+ {
61+ struct devfreq *devfreq;
62+ struct devfreq_governor *governor;
63++ unsigned long min_freq, max_freq;
64+ int err = 0;
65+
66+ if (!dev || !profile || !governor_name) {
67+@@ -849,6 +851,8 @@ struct devfreq *devfreq_add_device(struc
68+ goto err_dev;
69+ }
70+
71++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
72++
73+ devfreq->suspend_freq = dev_pm_opp_get_suspend_opp_freq(dev);
74+ devfreq->opp_table = dev_pm_opp_get_opp_table(dev);
75+ if (IS_ERR(devfreq->opp_table))
76+@@ -1561,7 +1565,7 @@ static ssize_t min_freq_show(struct devi
77+ unsigned long min_freq, max_freq;
78+
79+ mutex_lock(&df->lock);
80+- get_freq_range(df, &min_freq, &max_freq);
81++ devfreq_get_freq_range(df, &min_freq, &max_freq);
82+ mutex_unlock(&df->lock);
83+
84+ return sprintf(buf, "%lu\n", min_freq);
85+@@ -1615,7 +1619,7 @@ static ssize_t max_freq_show(struct devi
86+ unsigned long min_freq, max_freq;
87+
88+ mutex_lock(&df->lock);
89+- get_freq_range(df, &min_freq, &max_freq);
90++ devfreq_get_freq_range(df, &min_freq, &max_freq);
91+ mutex_unlock(&df->lock);
92+
93+ return sprintf(buf, "%lu\n", max_freq);
94+@@ -1929,7 +1933,7 @@ static int devfreq_summary_show(struct s
95+
96+ mutex_lock(&devfreq->lock);
97+ cur_freq = devfreq->previous_freq;
98+- get_freq_range(devfreq, &min_freq, &max_freq);
99++ devfreq_get_freq_range(devfreq, &min_freq, &max_freq);
100+ timer = devfreq->profile->timer;
101+
102+ if (IS_SUPPORTED_ATTR(devfreq->governor->attrs, POLLING_INTERVAL))
103+--- a/drivers/devfreq/governor.h
104++++ b/drivers/devfreq/governor.h
105+@@ -86,6 +86,8 @@ int devfreq_remove_governor(struct devfr
106+
107+ int devfreq_update_status(struct devfreq *devfreq, unsigned long freq);
108+ int devfreq_update_target(struct devfreq *devfreq, unsigned long freq);
109++void devfreq_get_freq_range(struct devfreq *devfreq, unsigned long *min_freq,
110++ unsigned long *max_freq);
111+
112+ static inline int devfreq_update_stats(struct devfreq *df)
113+ {
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/111-v5.19-02-PM-devfreq-Add-cpu-based-scaling-support-to-passive-.patch
@@ -0,0 +1,461 @@
1+From a03dacb0316f74400846aaf144d6c73f4217ca08 Mon Sep 17 00:00:00 2001
2+From: Saravana Kannan <skannan@codeaurora.org>
3+Date: Tue, 2 Mar 2021 15:58:21 +0900
4+Subject: [PATCH 2/5] PM / devfreq: Add cpu based scaling support to passive
5+ governor
6+
7+Many CPU architectures have caches that can scale independent of the
8+CPUs. Frequency scaling of the caches is necessary to make sure that the
9+cache is not a performance bottleneck that leads to poor performance and
10+power. The same idea applies for RAM/DDR.
11+
12+To achieve this, this patch adds support for cpu based scaling to the
13+passive governor. This is accomplished by taking the current frequency
14+of each CPU frequency domain and then adjust the frequency of the cache
15+(or any devfreq device) based on the frequency of the CPUs. It listens
16+to CPU frequency transition notifiers to keep itself up to date on the
17+current CPU frequency.
18+
19+To decide the frequency of the device, the governor does one of the
20+following:
21+* Derives the optimal devfreq device opp from required-opps property of
22+ the parent cpu opp_table.
23+
24+* Scales the device frequency in proportion to the CPU frequency. So, if
25+ the CPUs are running at their max frequency, the device runs at its
26+ max frequency. If the CPUs are running at their min frequency, the
27+ device runs at its min frequency. It is interpolated for frequencies
28+ in between.
29+
30+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
31+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
32+Signed-off-by: Saravana Kannan <skannan@codeaurora.org>
33+[Sibi: Integrated cpu-freqmap governor into passive_governor]
34+Signed-off-by: Sibi Sankar <sibis@codeaurora.org>
35+[Chanwoo: Fix conflict with latest code and cleanup code]
36+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
37+---
38+ drivers/devfreq/governor.h | 22 +++
39+ drivers/devfreq/governor_passive.c | 298 +++++++++++++++++++++++++++--
40+ include/linux/devfreq.h | 17 +-
41+ 3 files changed, 323 insertions(+), 14 deletions(-)
42+
43+--- a/drivers/devfreq/governor.h
44++++ b/drivers/devfreq/governor.h
45+@@ -48,6 +48,28 @@
46+ #define DEVFREQ_GOV_ATTR_TIMER BIT(1)
47+
48+ /**
49++ * struct devfreq_cpu_data - Hold the per-cpu data
50++ * @dev: reference to cpu device.
51++ * @first_cpu: the cpumask of the first cpu of a policy.
52++ * @opp_table: reference to cpu opp table.
53++ * @cur_freq: the current frequency of the cpu.
54++ * @min_freq: the min frequency of the cpu.
55++ * @max_freq: the max frequency of the cpu.
56++ *
57++ * This structure stores the required cpu_data of a cpu.
58++ * This is auto-populated by the governor.
59++ */
60++struct devfreq_cpu_data {
61++ struct device *dev;
62++ unsigned int first_cpu;
63++
64++ struct opp_table *opp_table;
65++ unsigned int cur_freq;
66++ unsigned int min_freq;
67++ unsigned int max_freq;
68++};
69++
70++/**
71+ * struct devfreq_governor - Devfreq policy governor
72+ * @node: list node - contains registered devfreq governors
73+ * @name: Governor's name
74+--- a/drivers/devfreq/governor_passive.c
75++++ b/drivers/devfreq/governor_passive.c
76+@@ -8,11 +8,85 @@
77+ */
78+
79+ #include <linux/module.h>
80++#include <linux/cpu.h>
81++#include <linux/cpufreq.h>
82++#include <linux/cpumask.h>
83++#include <linux/slab.h>
84+ #include <linux/device.h>
85+ #include <linux/devfreq.h>
86+ #include "governor.h"
87+
88+-static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
89++#define HZ_PER_KHZ 1000
90++
91++static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
92++ struct opp_table *p_opp_table,
93++ struct opp_table *opp_table,
94++ unsigned long *freq)
95++{
96++ struct dev_pm_opp *opp = NULL, *p_opp = NULL;
97++ unsigned long target_freq;
98++
99++ if (!p_dev || !p_opp_table || !opp_table || !freq)
100++ return 0;
101++
102++ p_opp = devfreq_recommended_opp(p_dev, freq, 0);
103++ if (IS_ERR(p_opp))
104++ return 0;
105++
106++ opp = dev_pm_opp_xlate_required_opp(p_opp_table, opp_table, p_opp);
107++ dev_pm_opp_put(p_opp);
108++
109++ if (IS_ERR(opp))
110++ return 0;
111++
112++ target_freq = dev_pm_opp_get_freq(opp);
113++ dev_pm_opp_put(opp);
114++
115++ return target_freq;
116++}
117++
118++static int get_target_freq_with_cpufreq(struct devfreq *devfreq,
119++ unsigned long *target_freq)
120++{
121++ struct devfreq_passive_data *p_data =
122++ (struct devfreq_passive_data *)devfreq->data;
123++ struct devfreq_cpu_data *parent_cpu_data;
124++ unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent;
125++ unsigned long dev_min, dev_max;
126++ unsigned long freq = 0;
127++
128++ for_each_online_cpu(cpu) {
129++ parent_cpu_data = p_data->parent_cpu_data[cpu];
130++ if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu)
131++ continue;
132++
133++ /* Get target freq via required opps */
134++ cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ;
135++ freq = get_target_freq_by_required_opp(parent_cpu_data->dev,
136++ parent_cpu_data->opp_table,
137++ devfreq->opp_table, &cpu_cur);
138++ if (freq) {
139++ *target_freq = max(freq, *target_freq);
140++ continue;
141++ }
142++
143++ /* Use interpolation if required opps is not available */
144++ devfreq_get_freq_range(devfreq, &dev_min, &dev_max);
145++
146++ cpu_min = parent_cpu_data->min_freq;
147++ cpu_max = parent_cpu_data->max_freq;
148++ cpu_cur = parent_cpu_data->cur_freq;
149++
150++ cpu_percent = ((cpu_cur - cpu_min) * 100) / (cpu_max - cpu_min);
151++ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100);
152++
153++ *target_freq = max(freq, *target_freq);
154++ }
155++
156++ return 0;
157++}
158++
159++static int get_target_freq_with_devfreq(struct devfreq *devfreq,
160+ unsigned long *freq)
161+ {
162+ struct devfreq_passive_data *p_data
163+@@ -99,6 +173,181 @@ no_required_opp:
164+ return 0;
165+ }
166+
167++static int devfreq_passive_get_target_freq(struct devfreq *devfreq,
168++ unsigned long *freq)
169++{
170++ struct devfreq_passive_data *p_data =
171++ (struct devfreq_passive_data *)devfreq->data;
172++ int ret;
173++
174++ if (!p_data)
175++ return -EINVAL;
176++
177++ /*
178++ * If the devfreq device with passive governor has the specific method
179++ * to determine the next frequency, should use the get_target_freq()
180++ * of struct devfreq_passive_data.
181++ */
182++ if (p_data->get_target_freq)
183++ return p_data->get_target_freq(devfreq, freq);
184++
185++ switch (p_data->parent_type) {
186++ case DEVFREQ_PARENT_DEV:
187++ ret = get_target_freq_with_devfreq(devfreq, freq);
188++ break;
189++ case CPUFREQ_PARENT_DEV:
190++ ret = get_target_freq_with_cpufreq(devfreq, freq);
191++ break;
192++ default:
193++ ret = -EINVAL;
194++ dev_err(&devfreq->dev, "Invalid parent type\n");
195++ break;
196++ }
197++
198++ return ret;
199++}
200++
201++static int cpufreq_passive_notifier_call(struct notifier_block *nb,
202++ unsigned long event, void *ptr)
203++{
204++ struct devfreq_passive_data *p_data =
205++ container_of(nb, struct devfreq_passive_data, nb);
206++ struct devfreq *devfreq = (struct devfreq *)p_data->this;
207++ struct devfreq_cpu_data *parent_cpu_data;
208++ struct cpufreq_freqs *freqs = ptr;
209++ unsigned int cur_freq;
210++ int ret;
211++
212++ if (event != CPUFREQ_POSTCHANGE || !freqs ||
213++ !p_data->parent_cpu_data[freqs->policy->cpu])
214++ return 0;
215++
216++ parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu];
217++ if (parent_cpu_data->cur_freq == freqs->new)
218++ return 0;
219++
220++ cur_freq = parent_cpu_data->cur_freq;
221++ parent_cpu_data->cur_freq = freqs->new;
222++
223++ mutex_lock(&devfreq->lock);
224++ ret = devfreq_update_target(devfreq, freqs->new);
225++ mutex_unlock(&devfreq->lock);
226++ if (ret) {
227++ parent_cpu_data->cur_freq = cur_freq;
228++ dev_err(&devfreq->dev, "failed to update the frequency.\n");
229++ return ret;
230++ }
231++
232++ return 0;
233++}
234++
235++static int cpufreq_passive_unregister_notifier(struct devfreq *devfreq)
236++{
237++ struct devfreq_passive_data *p_data
238++ = (struct devfreq_passive_data *)devfreq->data;
239++ struct devfreq_cpu_data *parent_cpu_data;
240++ int cpu, ret;
241++
242++ if (p_data->nb.notifier_call) {
243++ ret = cpufreq_unregister_notifier(&p_data->nb,
244++ CPUFREQ_TRANSITION_NOTIFIER);
245++ if (ret < 0)
246++ return ret;
247++ }
248++
249++ for_each_possible_cpu(cpu) {
250++ parent_cpu_data = p_data->parent_cpu_data[cpu];
251++ if (!parent_cpu_data)
252++ continue;
253++
254++ if (parent_cpu_data->opp_table)
255++ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
256++ kfree(parent_cpu_data);
257++ }
258++
259++ return 0;
260++}
261++
262++static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
263++{
264++ struct devfreq_passive_data *p_data
265++ = (struct devfreq_passive_data *)devfreq->data;
266++ struct device *dev = devfreq->dev.parent;
267++ struct opp_table *opp_table = NULL;
268++ struct devfreq_cpu_data *parent_cpu_data;
269++ struct cpufreq_policy *policy;
270++ struct device *cpu_dev;
271++ unsigned int cpu;
272++ int ret;
273++
274++ p_data->nb.notifier_call = cpufreq_passive_notifier_call;
275++ ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER);
276++ if (ret) {
277++ dev_err(dev, "failed to register cpufreq notifier\n");
278++ p_data->nb.notifier_call = NULL;
279++ goto err;
280++ }
281++
282++ for_each_possible_cpu(cpu) {
283++ if (p_data->parent_cpu_data[cpu])
284++ continue;
285++
286++ policy = cpufreq_cpu_get(cpu);
287++ if (!policy) {
288++ ret = -EPROBE_DEFER;
289++ goto err;
290++ }
291++
292++ parent_cpu_data = kzalloc(sizeof(*parent_cpu_data),
293++ GFP_KERNEL);
294++ if (!parent_cpu_data) {
295++ ret = -ENOMEM;
296++ goto err_put_policy;
297++ }
298++
299++ cpu_dev = get_cpu_device(cpu);
300++ if (!cpu_dev) {
301++ dev_err(dev, "failed to get cpu device\n");
302++ ret = -ENODEV;
303++ goto err_free_cpu_data;
304++ }
305++
306++ opp_table = dev_pm_opp_get_opp_table(cpu_dev);
307++ if (IS_ERR(opp_table)) {
308++ dev_err(dev, "failed to get opp_table of cpu%d\n", cpu);
309++ ret = PTR_ERR(opp_table);
310++ goto err_free_cpu_data;
311++ }
312++
313++ parent_cpu_data->dev = cpu_dev;
314++ parent_cpu_data->opp_table = opp_table;
315++ parent_cpu_data->first_cpu = cpumask_first(policy->related_cpus);
316++ parent_cpu_data->cur_freq = policy->cur;
317++ parent_cpu_data->min_freq = policy->cpuinfo.min_freq;
318++ parent_cpu_data->max_freq = policy->cpuinfo.max_freq;
319++
320++ p_data->parent_cpu_data[cpu] = parent_cpu_data;
321++ cpufreq_cpu_put(policy);
322++ }
323++
324++ mutex_lock(&devfreq->lock);
325++ ret = devfreq_update_target(devfreq, 0L);
326++ mutex_unlock(&devfreq->lock);
327++ if (ret)
328++ dev_err(dev, "failed to update the frequency\n");
329++
330++ return ret;
331++
332++err_free_cpu_data:
333++ kfree(parent_cpu_data);
334++err_put_policy:
335++ cpufreq_cpu_put(policy);
336++err:
337++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
338++
339++ return ret;
340++}
341++
342+ static int devfreq_passive_notifier_call(struct notifier_block *nb,
343+ unsigned long event, void *ptr)
344+ {
345+@@ -131,30 +380,55 @@ static int devfreq_passive_notifier_call
346+ return NOTIFY_DONE;
347+ }
348+
349+-static int devfreq_passive_event_handler(struct devfreq *devfreq,
350+- unsigned int event, void *data)
351++static int devfreq_passive_unregister_notifier(struct devfreq *devfreq)
352++{
353++ struct devfreq_passive_data *p_data
354++ = (struct devfreq_passive_data *)devfreq->data;
355++ struct devfreq *parent = (struct devfreq *)p_data->parent;
356++ struct notifier_block *nb = &p_data->nb;
357++
358++ return devfreq_unregister_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER);
359++}
360++
361++static int devfreq_passive_register_notifier(struct devfreq *devfreq)
362+ {
363+ struct devfreq_passive_data *p_data
364+ = (struct devfreq_passive_data *)devfreq->data;
365+ struct devfreq *parent = (struct devfreq *)p_data->parent;
366+ struct notifier_block *nb = &p_data->nb;
367+- int ret = 0;
368+
369+ if (!parent)
370+ return -EPROBE_DEFER;
371+
372++ nb->notifier_call = devfreq_passive_notifier_call;
373++ return devfreq_register_notifier(parent, nb, DEVFREQ_TRANSITION_NOTIFIER);
374++}
375++
376++static int devfreq_passive_event_handler(struct devfreq *devfreq,
377++ unsigned int event, void *data)
378++{
379++ struct devfreq_passive_data *p_data
380++ = (struct devfreq_passive_data *)devfreq->data;
381++ int ret = -EINVAL;
382++
383++ if (!p_data)
384++ return -EINVAL;
385++
386++ if (!p_data->this)
387++ p_data->this = devfreq;
388++
389+ switch (event) {
390+ case DEVFREQ_GOV_START:
391+- if (!p_data->this)
392+- p_data->this = devfreq;
393+-
394+- nb->notifier_call = devfreq_passive_notifier_call;
395+- ret = devfreq_register_notifier(parent, nb,
396+- DEVFREQ_TRANSITION_NOTIFIER);
397++ if (p_data->parent_type == DEVFREQ_PARENT_DEV)
398++ ret = devfreq_passive_register_notifier(devfreq);
399++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV)
400++ ret = cpufreq_passive_register_notifier(devfreq);
401+ break;
402+ case DEVFREQ_GOV_STOP:
403+- WARN_ON(devfreq_unregister_notifier(parent, nb,
404+- DEVFREQ_TRANSITION_NOTIFIER));
405++ if (p_data->parent_type == DEVFREQ_PARENT_DEV)
406++ WARN_ON(devfreq_passive_unregister_notifier(devfreq));
407++ else if (p_data->parent_type == CPUFREQ_PARENT_DEV)
408++ WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
409+ break;
410+ default:
411+ break;
412+--- a/include/linux/devfreq.h
413++++ b/include/linux/devfreq.h
414+@@ -38,6 +38,7 @@ enum devfreq_timer {
415+
416+ struct devfreq;
417+ struct devfreq_governor;
418++struct devfreq_cpu_data;
419+ struct thermal_cooling_device;
420+
421+ /**
422+@@ -288,6 +289,11 @@ struct devfreq_simple_ondemand_data {
423+ #endif
424+
425+ #if IS_ENABLED(CONFIG_DEVFREQ_GOV_PASSIVE)
426++enum devfreq_parent_dev_type {
427++ DEVFREQ_PARENT_DEV,
428++ CPUFREQ_PARENT_DEV,
429++};
430++
431+ /**
432+ * struct devfreq_passive_data - ``void *data`` fed to struct devfreq
433+ * and devfreq_add_device
434+@@ -299,8 +305,11 @@ struct devfreq_simple_ondemand_data {
435+ * using governors except for passive governor.
436+ * If the devfreq device has the specific method to decide
437+ * the next frequency, should use this callback.
438+- * @this: the devfreq instance of own device.
439+- * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER list
440++ * @parent_type: the parent type of the device.
441++ * @this: the devfreq instance of own device.
442++ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or
443++ * CPUFREQ_TRANSITION_NOTIFIER list.
444++ * @parent_cpu_data: the state min/max/current frequency of all online cpu's.
445+ *
446+ * The devfreq_passive_data have to set the devfreq instance of parent
447+ * device with governors except for the passive governor. But, don't need to
448+@@ -314,9 +323,13 @@ struct devfreq_passive_data {
449+ /* Optional callback to decide the next frequency of passvice device */
450+ int (*get_target_freq)(struct devfreq *this, unsigned long *freq);
451+
452++ /* Should set the type of parent device */
453++ enum devfreq_parent_dev_type parent_type;
454++
455+ /* For passive governor's internal use. Don't need to set them */
456+ struct devfreq *this;
457+ struct notifier_block nb;
458++ struct devfreq_cpu_data *parent_cpu_data[NR_CPUS];
459+ };
460+ #endif
461+
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/111-v5.19-03-PM-devfreq-passive-Reduce-duplicate-code-when-passiv.patch
@@ -0,0 +1,110 @@
1+From 05723e71234b60a1a47313ea1a889797ec648f1c Mon Sep 17 00:00:00 2001
2+From: Chanwoo Choi <cw00.choi@samsung.com>
3+Date: Tue, 2 Mar 2021 17:22:50 +0900
4+Subject: [PATCH 3/5] PM / devfreq: passive: Reduce duplicate code when
5+ passive_devfreq case
6+
7+In order to keep the consistent coding style between passive_devfreq
8+and passive_cpufreq, use common code for handling required opp property.
9+Also remove the unneed conditional statement and unify the comment
10+of both passive_devfreq and passive_cpufreq when getting the target frequency.
11+
12+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
13+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
14+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
15+---
16+ drivers/devfreq/governor_passive.c | 66 ++++--------------------------
17+ 1 file changed, 8 insertions(+), 58 deletions(-)
18+
19+--- a/drivers/devfreq/governor_passive.c
20++++ b/drivers/devfreq/governor_passive.c
21+@@ -93,65 +93,16 @@ static int get_target_freq_with_devfreq(
22+ = (struct devfreq_passive_data *)devfreq->data;
23+ struct devfreq *parent_devfreq = (struct devfreq *)p_data->parent;
24+ unsigned long child_freq = ULONG_MAX;
25+- struct dev_pm_opp *opp, *p_opp;
26+ int i, count;
27+
28+- /*
29+- * If the devfreq device with passive governor has the specific method
30+- * to determine the next frequency, should use the get_target_freq()
31+- * of struct devfreq_passive_data.
32+- */
33+- if (p_data->get_target_freq)
34+- return p_data->get_target_freq(devfreq, freq);
35+-
36+- /*
37+- * If the parent and passive devfreq device uses the OPP table,
38+- * get the next frequency by using the OPP table.
39+- */
40+-
41+- /*
42+- * - parent devfreq device uses the governors except for passive.
43+- * - passive devfreq device uses the passive governor.
44+- *
45+- * Each devfreq has the OPP table. After deciding the new frequency
46+- * from the governor of parent devfreq device, the passive governor
47+- * need to get the index of new frequency on OPP table of parent
48+- * device. And then the index is used for getting the suitable
49+- * new frequency for passive devfreq device.
50+- */
51+- if (!devfreq->profile || !devfreq->profile->freq_table
52+- || devfreq->profile->max_state <= 0)
53+- return -EINVAL;
54+-
55+- /*
56+- * The passive governor have to get the correct frequency from OPP
57+- * list of parent device. Because in this case, *freq is temporary
58+- * value which is decided by ondemand governor.
59+- */
60+- if (devfreq->opp_table && parent_devfreq->opp_table) {
61+- p_opp = devfreq_recommended_opp(parent_devfreq->dev.parent,
62+- freq, 0);
63+- if (IS_ERR(p_opp))
64+- return PTR_ERR(p_opp);
65+-
66+- opp = dev_pm_opp_xlate_required_opp(parent_devfreq->opp_table,
67+- devfreq->opp_table, p_opp);
68+- dev_pm_opp_put(p_opp);
69+-
70+- if (IS_ERR(opp))
71+- goto no_required_opp;
72+-
73+- *freq = dev_pm_opp_get_freq(opp);
74+- dev_pm_opp_put(opp);
75+-
76+- return 0;
77+- }
78++ /* Get target freq via required opps */
79++ child_freq = get_target_freq_by_required_opp(parent_devfreq->dev.parent,
80++ parent_devfreq->opp_table,
81++ devfreq->opp_table, freq);
82++ if (child_freq)
83++ goto out;
84+
85+-no_required_opp:
86+- /*
87+- * Get the OPP table's index of decided frequency by governor
88+- * of parent device.
89+- */
90++ /* Use interpolation if required opps is not available */
91+ for (i = 0; i < parent_devfreq->profile->max_state; i++)
92+ if (parent_devfreq->profile->freq_table[i] == *freq)
93+ break;
94+@@ -159,7 +110,6 @@ no_required_opp:
95+ if (i == parent_devfreq->profile->max_state)
96+ return -EINVAL;
97+
98+- /* Get the suitable frequency by using index of parent device. */
99+ if (i < devfreq->profile->max_state) {
100+ child_freq = devfreq->profile->freq_table[i];
101+ } else {
102+@@ -167,7 +117,7 @@ no_required_opp:
103+ child_freq = devfreq->profile->freq_table[count - 1];
104+ }
105+
106+- /* Return the suitable frequency for passive device. */
107++out:
108+ *freq = child_freq;
109+
110+ return 0;
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch
@@ -0,0 +1,232 @@
1+From 26984d9d581e5049bd75091d2e789b9cc3ea12e0 Mon Sep 17 00:00:00 2001
2+From: Chanwoo Choi <cw00.choi@samsung.com>
3+Date: Wed, 27 Apr 2022 03:49:19 +0900
4+Subject: [PATCH 4/5] PM / devfreq: passive: Keep cpufreq_policy for possible
5+ cpus
6+
7+The passive governor requires the cpu data to get the next target frequency
8+of devfreq device if depending on cpu. In order to reduce the unnecessary
9+memory data, keep cpufreq_policy data for possible cpus instead of NR_CPU.
10+
11+Tested-by: Chen-Yu Tsai <wenst@chromium.org>
12+Tested-by: Johnson Wang <johnson.wang@mediatek.com>
13+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
14+---
15+ drivers/devfreq/governor.h | 3 ++
16+ drivers/devfreq/governor_passive.c | 75 +++++++++++++++++++++++-------
17+ include/linux/devfreq.h | 4 +-
18+ 3 files changed, 64 insertions(+), 18 deletions(-)
19+
20+--- a/drivers/devfreq/governor.h
21++++ b/drivers/devfreq/governor.h
22+@@ -49,6 +49,7 @@
23+
24+ /**
25+ * struct devfreq_cpu_data - Hold the per-cpu data
26++ * @node: list node
27+ * @dev: reference to cpu device.
28+ * @first_cpu: the cpumask of the first cpu of a policy.
29+ * @opp_table: reference to cpu opp table.
30+@@ -60,6 +61,8 @@
31+ * This is auto-populated by the governor.
32+ */
33+ struct devfreq_cpu_data {
34++ struct list_head node;
35++
36+ struct device *dev;
37+ unsigned int first_cpu;
38+
39+--- a/drivers/devfreq/governor_passive.c
40++++ b/drivers/devfreq/governor_passive.c
41+@@ -1,4 +1,4 @@
42+-// SPDX-License-Identifier: GPL-2.0-only
43++ // SPDX-License-Identifier: GPL-2.0-only
44+ /*
45+ * linux/drivers/devfreq/governor_passive.c
46+ *
47+@@ -18,6 +18,22 @@
48+
49+ #define HZ_PER_KHZ 1000
50+
51++static struct devfreq_cpu_data *
52++get_parent_cpu_data(struct devfreq_passive_data *p_data,
53++ struct cpufreq_policy *policy)
54++{
55++ struct devfreq_cpu_data *parent_cpu_data;
56++
57++ if (!p_data || !policy)
58++ return NULL;
59++
60++ list_for_each_entry(parent_cpu_data, &p_data->cpu_data_list, node)
61++ if (parent_cpu_data->first_cpu == cpumask_first(policy->related_cpus))
62++ return parent_cpu_data;
63++
64++ return NULL;
65++}
66++
67+ static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
68+ struct opp_table *p_opp_table,
69+ struct opp_table *opp_table,
70+@@ -51,14 +67,24 @@ static int get_target_freq_with_cpufreq(
71+ struct devfreq_passive_data *p_data =
72+ (struct devfreq_passive_data *)devfreq->data;
73+ struct devfreq_cpu_data *parent_cpu_data;
74++ struct cpufreq_policy *policy;
75+ unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent;
76+ unsigned long dev_min, dev_max;
77+ unsigned long freq = 0;
78++ int ret = 0;
79+
80+ for_each_online_cpu(cpu) {
81+- parent_cpu_data = p_data->parent_cpu_data[cpu];
82+- if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu)
83++ policy = cpufreq_cpu_get(cpu);
84++ if (!policy) {
85++ ret = -EINVAL;
86++ continue;
87++ }
88++
89++ parent_cpu_data = get_parent_cpu_data(p_data, policy);
90++ if (!parent_cpu_data) {
91++ cpufreq_cpu_put(policy);
92+ continue;
93++ }
94+
95+ /* Get target freq via required opps */
96+ cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ;
97+@@ -67,6 +93,7 @@ static int get_target_freq_with_cpufreq(
98+ devfreq->opp_table, &cpu_cur);
99+ if (freq) {
100+ *target_freq = max(freq, *target_freq);
101++ cpufreq_cpu_put(policy);
102+ continue;
103+ }
104+
105+@@ -81,9 +108,10 @@ static int get_target_freq_with_cpufreq(
106+ freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100);
107+
108+ *target_freq = max(freq, *target_freq);
109++ cpufreq_cpu_put(policy);
110+ }
111+
112+- return 0;
113++ return ret;
114+ }
115+
116+ static int get_target_freq_with_devfreq(struct devfreq *devfreq,
117+@@ -168,12 +196,11 @@ static int cpufreq_passive_notifier_call
118+ unsigned int cur_freq;
119+ int ret;
120+
121+- if (event != CPUFREQ_POSTCHANGE || !freqs ||
122+- !p_data->parent_cpu_data[freqs->policy->cpu])
123++ if (event != CPUFREQ_POSTCHANGE || !freqs)
124+ return 0;
125+
126+- parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu];
127+- if (parent_cpu_data->cur_freq == freqs->new)
128++ parent_cpu_data = get_parent_cpu_data(p_data, freqs->policy);
129++ if (!parent_cpu_data || parent_cpu_data->cur_freq == freqs->new)
130+ return 0;
131+
132+ cur_freq = parent_cpu_data->cur_freq;
133+@@ -196,7 +223,7 @@ static int cpufreq_passive_unregister_no
134+ struct devfreq_passive_data *p_data
135+ = (struct devfreq_passive_data *)devfreq->data;
136+ struct devfreq_cpu_data *parent_cpu_data;
137+- int cpu, ret;
138++ int cpu, ret = 0;
139+
140+ if (p_data->nb.notifier_call) {
141+ ret = cpufreq_unregister_notifier(&p_data->nb,
142+@@ -206,16 +233,26 @@ static int cpufreq_passive_unregister_no
143+ }
144+
145+ for_each_possible_cpu(cpu) {
146+- parent_cpu_data = p_data->parent_cpu_data[cpu];
147+- if (!parent_cpu_data)
148++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
149++ if (!policy) {
150++ ret = -EINVAL;
151++ continue;
152++ }
153++
154++ parent_cpu_data = get_parent_cpu_data(p_data, policy);
155++ if (!parent_cpu_data) {
156++ cpufreq_cpu_put(policy);
157+ continue;
158++ }
159+
160++ list_del(&parent_cpu_data->node);
161+ if (parent_cpu_data->opp_table)
162+ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
163+ kfree(parent_cpu_data);
164++ cpufreq_cpu_put(policy);
165+ }
166+
167+- return 0;
168++ return ret;
169+ }
170+
171+ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
172+@@ -230,6 +267,9 @@ static int cpufreq_passive_register_noti
173+ unsigned int cpu;
174+ int ret;
175+
176++ p_data->cpu_data_list
177++ = (struct list_head)LIST_HEAD_INIT(p_data->cpu_data_list);
178++
179+ p_data->nb.notifier_call = cpufreq_passive_notifier_call;
180+ ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER);
181+ if (ret) {
182+@@ -239,15 +279,18 @@ static int cpufreq_passive_register_noti
183+ }
184+
185+ for_each_possible_cpu(cpu) {
186+- if (p_data->parent_cpu_data[cpu])
187+- continue;
188+-
189+ policy = cpufreq_cpu_get(cpu);
190+ if (!policy) {
191+ ret = -EPROBE_DEFER;
192+ goto err;
193+ }
194+
195++ parent_cpu_data = get_parent_cpu_data(p_data, policy);
196++ if (parent_cpu_data) {
197++ cpufreq_cpu_put(policy);
198++ continue;
199++ }
200++
201+ parent_cpu_data = kzalloc(sizeof(*parent_cpu_data),
202+ GFP_KERNEL);
203+ if (!parent_cpu_data) {
204+@@ -276,7 +319,7 @@ static int cpufreq_passive_register_noti
205+ parent_cpu_data->min_freq = policy->cpuinfo.min_freq;
206+ parent_cpu_data->max_freq = policy->cpuinfo.max_freq;
207+
208+- p_data->parent_cpu_data[cpu] = parent_cpu_data;
209++ list_add_tail(&parent_cpu_data->node, &p_data->cpu_data_list);
210+ cpufreq_cpu_put(policy);
211+ }
212+
213+--- a/include/linux/devfreq.h
214++++ b/include/linux/devfreq.h
215+@@ -309,7 +309,7 @@ enum devfreq_parent_dev_type {
216+ * @this: the devfreq instance of own device.
217+ * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or
218+ * CPUFREQ_TRANSITION_NOTIFIER list.
219+- * @parent_cpu_data: the state min/max/current frequency of all online cpu's.
220++ * @cpu_data_list: the list of cpu frequency data for all cpufreq_policy.
221+ *
222+ * The devfreq_passive_data have to set the devfreq instance of parent
223+ * device with governors except for the passive governor. But, don't need to
224+@@ -329,7 +329,7 @@ struct devfreq_passive_data {
225+ /* For passive governor's internal use. Don't need to set them */
226+ struct devfreq *this;
227+ struct notifier_block nb;
228+- struct devfreq_cpu_data *parent_cpu_data[NR_CPUS];
229++ struct list_head cpu_data_list;
230+ };
231+ #endif
232+
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/111-v5.19-05-PM-devfreq-passive-Return-non-error-when-not-support.patch
@@ -0,0 +1,31 @@
1+From 42d2607d91c4ec37ea1970899c2d614824f3014b Mon Sep 17 00:00:00 2001
2+From: Chanwoo Choi <cw00.choi@samsung.com>
3+Date: Thu, 19 May 2022 10:07:53 +0900
4+Subject: [PATCH 5/5] PM / devfreq: passive: Return non-error when
5+ not-supported event is required
6+
7+Each devfreq governor specifies the supported governor event
8+such as GOV_START and GOV_STOP. When not-supported event is required,
9+just return non-error. But, commit ce9a0d88d97a ("PM / devfreq: Add
10+cpu based scaling support to passive governor") returned the error
11+value. So that return non-error value when not-supported event is required.
12+
13+Fixes: ce9a0d88d97a ("PM / devfreq: Add cpu based scaling support to passive governor")
14+Reported-by: Marek Szyprowski <m.szyprowski@samsung.com>
15+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
16+Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
17+---
18+ drivers/devfreq/governor_passive.c | 2 +-
19+ 1 file changed, 1 insertion(+), 1 deletion(-)
20+
21+--- a/drivers/devfreq/governor_passive.c
22++++ b/drivers/devfreq/governor_passive.c
23+@@ -402,7 +402,7 @@ static int devfreq_passive_event_handler
24+ {
25+ struct devfreq_passive_data *p_data
26+ = (struct devfreq_passive_data *)devfreq->data;
27+- int ret = -EINVAL;
28++ int ret = 0;
29+
30+ if (!p_data)
31+ return -EINVAL;
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/112-v5.19-PM-devfreq-Fix-kernel-warning-with-cpufreq-passive-r.patch
@@ -0,0 +1,31 @@
1+From 82c66d2bbbeda9e493487e7413769087a0b46250 Mon Sep 17 00:00:00 2001
2+From: Christian Marangi <ansuelsmth@gmail.com>
3+Date: Mon, 20 Jun 2022 00:29:39 +0200
4+Subject: [PATCH 1/1] PM / devfreq: Fix kernel warning with cpufreq passive
5+ register fail
6+
7+Remove cpufreq_passive_unregister_notifier from
8+cpufreq_passive_register_notifier in case of error as devfreq core
9+already call unregister on GOV_START fail.
10+
11+This fix the kernel always printing a WARN on governor PROBE_DEFER as
12+cpufreq_passive_unregister_notifier is called two times and return
13+error on the second call as the cpufreq is already unregistered.
14+
15+Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
16+Signed-off-by: Christian Marangi <ansuelsmth@gmail.com>
17+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
18+---
19+ drivers/devfreq/governor_passive.c | 1 -
20+ 1 file changed, 1 deletion(-)
21+
22+--- a/drivers/devfreq/governor_passive.c
23++++ b/drivers/devfreq/governor_passive.c
24+@@ -336,7 +336,6 @@ err_free_cpu_data:
25+ err_put_policy:
26+ cpufreq_cpu_put(policy);
27+ err:
28+- WARN_ON(cpufreq_passive_unregister_notifier(devfreq));
29+
30+ return ret;
31+ }
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/113-v5.19-01-PM-devfreq-Fix-cpufreq-passive-unregister-errorin.patch
@@ -0,0 +1,85 @@
1+From 8953603eb5447be52f6fc3d8fcae1b3ce9899189 Mon Sep 17 00:00:00 2001
2+From: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
3+Date: Mon, 6 Jun 2022 11:58:49 +0200
4+Subject: [PATCH v4 1/4] PM / devfreq: Fix cpufreq passive unregister erroring
5+ on PROBE_DEFER
6+
7+With the passive governor, the cpu based scaling can PROBE_DEFER due to
8+the fact that CPU policy are not ready.
9+The cpufreq passive unregister notifier is called both from the
10+GOV_START errors and for the GOV_STOP and assume the notifier is
11+successfully registred every time. With GOV_START failing it's wrong to
12+loop over each possible CPU since the register path has failed for
13+some CPU policy not ready. Change the logic and unregister the notifer
14+based on the current allocated parent_cpu_data list to correctly handle
15+errors and the governor unregister path.
16+
17+Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
18+Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
19+---
20+ drivers/devfreq/governor_passive.c | 39 +++++++++++++-----------------
21+ 1 file changed, 17 insertions(+), 22 deletions(-)
22+
23+--- a/drivers/devfreq/governor_passive.c
24++++ b/drivers/devfreq/governor_passive.c
25+@@ -34,6 +34,20 @@ get_parent_cpu_data(struct devfreq_passi
26+ return NULL;
27+ }
28+
29++static void delete_parent_cpu_data(struct devfreq_passive_data *p_data)
30++{
31++ struct devfreq_cpu_data *parent_cpu_data, *tmp;
32++
33++ list_for_each_entry_safe(parent_cpu_data, tmp, &p_data->cpu_data_list, node) {
34++ list_del(&parent_cpu_data->node);
35++
36++ if (parent_cpu_data->opp_table)
37++ dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
38++
39++ kfree(parent_cpu_data);
40++ }
41++}
42++
43+ static unsigned long get_target_freq_by_required_opp(struct device *p_dev,
44+ struct opp_table *p_opp_table,
45+ struct opp_table *opp_table,
46+@@ -222,8 +236,7 @@ static int cpufreq_passive_unregister_no
47+ {
48+ struct devfreq_passive_data *p_data
49+ = (struct devfreq_passive_data *)devfreq->data;
50+- struct devfreq_cpu_data *parent_cpu_data;
51+- int cpu, ret = 0;
52++ int ret;
53+
54+ if (p_data->nb.notifier_call) {
55+ ret = cpufreq_unregister_notifier(&p_data->nb,
56+@@ -232,27 +245,9 @@ static int cpufreq_passive_unregister_no
57+ return ret;
58+ }
59+
60+- for_each_possible_cpu(cpu) {
61+- struct cpufreq_policy *policy = cpufreq_cpu_get(cpu);
62+- if (!policy) {
63+- ret = -EINVAL;
64+- continue;
65+- }
66+-
67+- parent_cpu_data = get_parent_cpu_data(p_data, policy);
68+- if (!parent_cpu_data) {
69+- cpufreq_cpu_put(policy);
70+- continue;
71+- }
72+-
73+- list_del(&parent_cpu_data->node);
74+- if (parent_cpu_data->opp_table)
75+- dev_pm_opp_put_opp_table(parent_cpu_data->opp_table);
76+- kfree(parent_cpu_data);
77+- cpufreq_cpu_put(policy);
78+- }
79++ delete_parent_cpu_data(p_data);
80+
81+- return ret;
82++ return 0;
83+ }
84+
85+ static int cpufreq_passive_register_notifier(struct devfreq *devfreq)
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/113-v5.19-02-PM-devfreq-Fix-kernel-panic-with-cpu-based-scaling-t.patch
@@ -0,0 +1,39 @@
1+From 57e00b40033a376de3f3cf0bb9bf7590d2dd679d Mon Sep 17 00:00:00 2001
2+From: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
3+Date: Tue, 14 Jun 2022 13:06:59 +0200
4+Subject: [PATCH 1/1] PM / devfreq: Fix kernel panic with cpu based scaling to
5+ passive gov
6+
7+The cpufreq passive register notifier can PROBE_DEFER and the devfreq
8+struct is freed and then reallocaed on probe retry.
9+The current logic assume that the code can't PROBE_DEFER so the devfreq
10+struct in the this variable in devfreq_passive_data is assumed to be
11+(if already set) always correct.
12+This cause kernel panic as the code try to access the wrong address.
13+To correctly handle this, update the this variable in
14+devfreq_passive_data to the devfreq reallocated struct.
15+
16+Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
17+Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
18+Signed-off-by: Chanwoo Choi <cw00.choi@samsung.com>
19+---
20+ drivers/devfreq/governor_passive.c | 3 +--
21+ 1 file changed, 1 insertion(+), 2 deletions(-)
22+
23+diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
24+index 72c67979ebe1..091a69e1f487 100644
25+--- a/drivers/devfreq/governor_passive.c
26++++ b/drivers/devfreq/governor_passive.c
27+@@ -407,8 +407,7 @@ static int devfreq_passive_event_handler(struct devfreq *devfreq,
28+ if (!p_data)
29+ return -EINVAL;
30+
31+- if (!p_data->this)
32+- p_data->this = devfreq;
33++ p_data->this = devfreq;
34+
35+ switch (event) {
36+ case DEVFREQ_GOV_START:
37+--
38+2.37.2
39+
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/113-v5.19-03-PM-devfreq-Rework-freq_table-to-be-local-to-devfr.patch
@@ -0,0 +1,269 @@
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+@@ -835,6 +831,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+@@ -870,8 +869,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+@@ -880,7 +879,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+@@ -1639,9 +1638,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+@@ -1664,7 +1663,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+@@ -1681,19 +1680,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+@@ -1717,7 +1714,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+@@ -1725,11 +1722,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+
--- /dev/null
+++ b/target/linux/ipq806x/patches-5.15/113-v5.19-04-PM-devfreq-Mute-warning-on-governor-PROBE_DEFER.patch
@@ -0,0 +1,28 @@
1+From eee9f767c41b03a2744d4b0f0c1a144e4ff41e78 Mon Sep 17 00:00:00 2001
2+From: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
3+Date: Mon, 6 Jun 2022 13:01:02 +0200
4+Subject: [PATCH v4 4/4] PM / devfreq: Mute warning on governor PROBE_DEFER
5+
6+Don't print warning when a governor PROBE_DEFER as it's not a real
7+GOV_START fail.
8+
9+Fixes: a03dacb0316f ("PM / devfreq: Add cpu based scaling support to passive governor")
10+Signed-off-by: Christian 'Ansuel' Marangi <ansuelsmth@gmail.com>
11+---
12+ drivers/devfreq/devfreq.c | 5 +++--
13+ 1 file changed, 3 insertions(+), 2 deletions(-)
14+
15+--- a/drivers/devfreq/devfreq.c
16++++ b/drivers/devfreq/devfreq.c
17+@@ -931,8 +931,9 @@ struct devfreq *devfreq_add_device(struc
18+ err = devfreq->governor->event_handler(devfreq, DEVFREQ_GOV_START,
19+ NULL);
20+ if (err) {
21+- dev_err(dev, "%s: Unable to start governor for the device\n",
22+- __func__);
23++ dev_err_probe(dev, err,
24++ "%s: Unable to start governor for the device\n",
25++ __func__);
26+ goto err_init;
27+ }
28+ create_sysfs_files(devfreq, devfreq->governor);