diff options
Diffstat (limited to 'target/linux/ipq806x/patches-5.15/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch')
-rw-r--r-- | target/linux/ipq806x/patches-5.15/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch | 232 |
1 files changed, 232 insertions, 0 deletions
diff --git a/target/linux/ipq806x/patches-5.15/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch b/target/linux/ipq806x/patches-5.15/111-v5.19-04-PM-devfreq-passive-Keep-cpufreq_policy-for-possible-.patch new file mode 100644 index 0000000000..12de8af22e --- /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 @@ +From 26984d9d581e5049bd75091d2e789b9cc3ea12e0 Mon Sep 17 00:00:00 2001 +From: Chanwoo Choi <cw00.choi@samsung.com> +Date: Wed, 27 Apr 2022 03:49:19 +0900 +Subject: [PATCH 4/5] 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> +--- + drivers/devfreq/governor.h | 3 ++ + drivers/devfreq/governor_passive.c | 75 +++++++++++++++++++++++------- + include/linux/devfreq.h | 4 +- + 3 files changed, 64 insertions(+), 18 deletions(-) + +--- a/drivers/devfreq/governor.h ++++ b/drivers/devfreq/governor.h +@@ -49,6 +49,7 @@ + + /** + * struct devfreq_cpu_data - Hold the per-cpu data ++ * @node: list node + * @dev: reference to cpu device. + * @first_cpu: the cpumask of the first cpu of a policy. + * @opp_table: reference to cpu opp table. +@@ -60,6 +61,8 @@ + * This is auto-populated by the governor. + */ + struct devfreq_cpu_data { ++ struct list_head node; ++ + struct device *dev; + unsigned int first_cpu; + +--- a/drivers/devfreq/governor_passive.c ++++ b/drivers/devfreq/governor_passive.c +@@ -1,4 +1,4 @@ +-// SPDX-License-Identifier: GPL-2.0-only ++ // SPDX-License-Identifier: GPL-2.0-only + /* + * linux/drivers/devfreq/governor_passive.c + * +@@ -18,6 +18,22 @@ + + #define HZ_PER_KHZ 1000 + ++static struct devfreq_cpu_data * ++get_parent_cpu_data(struct devfreq_passive_data *p_data, ++ struct cpufreq_policy *policy) ++{ ++ struct devfreq_cpu_data *parent_cpu_data; ++ ++ if (!p_data || !policy) ++ return NULL; ++ ++ list_for_each_entry(parent_cpu_data, &p_data->cpu_data_list, node) ++ if (parent_cpu_data->first_cpu == cpumask_first(policy->related_cpus)) ++ return parent_cpu_data; ++ ++ return NULL; ++} ++ + static unsigned long get_target_freq_by_required_opp(struct device *p_dev, + struct opp_table *p_opp_table, + struct opp_table *opp_table, +@@ -51,14 +67,24 @@ static int get_target_freq_with_cpufreq( + struct devfreq_passive_data *p_data = + (struct devfreq_passive_data *)devfreq->data; + struct devfreq_cpu_data *parent_cpu_data; ++ struct cpufreq_policy *policy; + unsigned long cpu, cpu_cur, cpu_min, cpu_max, cpu_percent; + unsigned long dev_min, dev_max; + unsigned long freq = 0; ++ int ret = 0; + + for_each_online_cpu(cpu) { +- parent_cpu_data = p_data->parent_cpu_data[cpu]; +- if (!parent_cpu_data || parent_cpu_data->first_cpu != cpu) ++ policy = cpufreq_cpu_get(cpu); ++ if (!policy) { ++ ret = -EINVAL; ++ continue; ++ } ++ ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (!parent_cpu_data) { ++ cpufreq_cpu_put(policy); + continue; ++ } + + /* Get target freq via required opps */ + cpu_cur = parent_cpu_data->cur_freq * HZ_PER_KHZ; +@@ -67,6 +93,7 @@ static int get_target_freq_with_cpufreq( + devfreq->opp_table, &cpu_cur); + if (freq) { + *target_freq = max(freq, *target_freq); ++ cpufreq_cpu_put(policy); + continue; + } + +@@ -81,9 +108,10 @@ static int get_target_freq_with_cpufreq( + freq = dev_min + mult_frac(dev_max - dev_min, cpu_percent, 100); + + *target_freq = max(freq, *target_freq); ++ cpufreq_cpu_put(policy); + } + +- return 0; ++ return ret; + } + + static int get_target_freq_with_devfreq(struct devfreq *devfreq, +@@ -168,12 +196,11 @@ static int cpufreq_passive_notifier_call + unsigned int cur_freq; + int ret; + +- if (event != CPUFREQ_POSTCHANGE || !freqs || +- !p_data->parent_cpu_data[freqs->policy->cpu]) ++ if (event != CPUFREQ_POSTCHANGE || !freqs) + return 0; + +- parent_cpu_data = p_data->parent_cpu_data[freqs->policy->cpu]; +- if (parent_cpu_data->cur_freq == freqs->new) ++ parent_cpu_data = get_parent_cpu_data(p_data, freqs->policy); ++ if (!parent_cpu_data || parent_cpu_data->cur_freq == freqs->new) + return 0; + + cur_freq = parent_cpu_data->cur_freq; +@@ -196,7 +223,7 @@ static int cpufreq_passive_unregister_no + struct devfreq_passive_data *p_data + = (struct devfreq_passive_data *)devfreq->data; + struct devfreq_cpu_data *parent_cpu_data; +- int cpu, ret; ++ int cpu, ret = 0; + + if (p_data->nb.notifier_call) { + ret = cpufreq_unregister_notifier(&p_data->nb, +@@ -206,16 +233,26 @@ static int cpufreq_passive_unregister_no + } + + for_each_possible_cpu(cpu) { +- parent_cpu_data = p_data->parent_cpu_data[cpu]; +- if (!parent_cpu_data) ++ struct cpufreq_policy *policy = cpufreq_cpu_get(cpu); ++ if (!policy) { ++ ret = -EINVAL; ++ continue; ++ } ++ ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (!parent_cpu_data) { ++ cpufreq_cpu_put(policy); + continue; ++ } + ++ list_del(&parent_cpu_data->node); + if (parent_cpu_data->opp_table) + dev_pm_opp_put_opp_table(parent_cpu_data->opp_table); + kfree(parent_cpu_data); ++ cpufreq_cpu_put(policy); + } + +- return 0; ++ return ret; + } + + static int cpufreq_passive_register_notifier(struct devfreq *devfreq) +@@ -230,6 +267,9 @@ static int cpufreq_passive_register_noti + unsigned int cpu; + int ret; + ++ p_data->cpu_data_list ++ = (struct list_head)LIST_HEAD_INIT(p_data->cpu_data_list); ++ + p_data->nb.notifier_call = cpufreq_passive_notifier_call; + ret = cpufreq_register_notifier(&p_data->nb, CPUFREQ_TRANSITION_NOTIFIER); + if (ret) { +@@ -239,15 +279,18 @@ static int cpufreq_passive_register_noti + } + + for_each_possible_cpu(cpu) { +- if (p_data->parent_cpu_data[cpu]) +- continue; +- + policy = cpufreq_cpu_get(cpu); + if (!policy) { + ret = -EPROBE_DEFER; + goto err; + } + ++ parent_cpu_data = get_parent_cpu_data(p_data, policy); ++ if (parent_cpu_data) { ++ cpufreq_cpu_put(policy); ++ continue; ++ } ++ + parent_cpu_data = kzalloc(sizeof(*parent_cpu_data), + GFP_KERNEL); + if (!parent_cpu_data) { +@@ -276,7 +319,7 @@ static int cpufreq_passive_register_noti + parent_cpu_data->min_freq = policy->cpuinfo.min_freq; + parent_cpu_data->max_freq = policy->cpuinfo.max_freq; + +- p_data->parent_cpu_data[cpu] = parent_cpu_data; ++ list_add_tail(&parent_cpu_data->node, &p_data->cpu_data_list); + cpufreq_cpu_put(policy); + } + +--- a/include/linux/devfreq.h ++++ b/include/linux/devfreq.h +@@ -309,7 +309,7 @@ enum devfreq_parent_dev_type { + * @this: the devfreq instance of own device. + * @nb: the notifier block for DEVFREQ_TRANSITION_NOTIFIER or + * CPUFREQ_TRANSITION_NOTIFIER list. +- * @parent_cpu_data: the state min/max/current frequency of all online cpu's. ++ * @cpu_data_list: the list of cpu frequency data for all cpufreq_policy. + * + * The devfreq_passive_data have to set the devfreq instance of parent + * device with governors except for the passive governor. But, don't need to +@@ -329,7 +329,7 @@ struct devfreq_passive_data { + /* For passive governor's internal use. Don't need to set them */ + struct devfreq *this; + struct notifier_block nb; +- struct devfreq_cpu_data *parent_cpu_data[NR_CPUS]; ++ struct list_head cpu_data_list; + }; + #endif + |