summaryrefslogtreecommitdiffstats
path: root/drivers/devfreq/governor_passive.c
diff options
context:
space:
mode:
authorChanwoo Choi <cw00.choi@samsung.com>2022-04-27 03:49:19 +0900
committerChanwoo Choi <cw00.choi@samsung.com>2022-05-17 18:24:39 +0900
commit26984d9d581e5049bd75091d2e789b9cc3ea12e0 (patch)
tree5d74ce9b6da36e719bd3db3b0c0cf11662df0a56 /drivers/devfreq/governor_passive.c
parent05723e71234b60a1a47313ea1a889797ec648f1c (diff)
downloadlinux-26984d9d581e5049bd75091d2e789b9cc3ea12e0.tar.bz2
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>
Diffstat (limited to 'drivers/devfreq/governor_passive.c')
-rw-r--r--drivers/devfreq/governor_passive.c75
1 files changed, 59 insertions, 16 deletions
diff --git a/drivers/devfreq/governor_passive.c b/drivers/devfreq/governor_passive.c
index ffcce613a48c..7306e943a234 100644
--- 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 *devfreq,
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(struct devfreq *devfreq,
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(struct devfreq *devfreq,
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(struct notifier_block *nb,
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_notifier(struct devfreq *devfreq)
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_notifier(struct devfreq *devfreq)
}
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_notifier(struct devfreq *devfreq)
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_notifier(struct devfreq *devfreq)
}
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_notifier(struct devfreq *devfreq)
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);
}