Skip to content

Commit 08a1000

Browse files
committed
Merge branch 'pm-cpufreq-sched'
* pm-cpufreq-sched: cpufreq: schedutil: Always process remote callback with slow switching cpufreq: schedutil: Don't restrict kthread to related_cpus unnecessarily cpufreq: Return 0 from ->fast_switch() on errors cpufreq: Simplify cpufreq_can_do_remote_dvfs() cpufreq: Process remote callbacks from any CPU if the platform permits sched: cpufreq: Allow remote cpufreq callbacks cpufreq: schedutil: Use unsigned int for iowait boost cpufreq: schedutil: Make iowait boost more energy efficient
2 parents bd87c8f + c49cbc1 commit 08a1000

File tree

10 files changed

+116
-31
lines changed

10 files changed

+116
-31
lines changed

drivers/cpufreq/cpufreq-dt.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -274,6 +274,7 @@ static int cpufreq_init(struct cpufreq_policy *policy)
274274
transition_latency = CPUFREQ_ETERNAL;
275275

276276
policy->cpuinfo.transition_latency = transition_latency;
277+
policy->dvfs_possible_from_any_cpu = true;
277278

278279
return 0;
279280

drivers/cpufreq/cpufreq.c

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1843,9 +1843,10 @@ EXPORT_SYMBOL(cpufreq_unregister_notifier);
18431843
* twice in parallel for the same policy and that it will never be called in
18441844
* parallel with either ->target() or ->target_index() for the same policy.
18451845
*
1846-
* If CPUFREQ_ENTRY_INVALID is returned by the driver's ->fast_switch()
1847-
* callback to indicate an error condition, the hardware configuration must be
1848-
* preserved.
1846+
* Returns the actual frequency set for the CPU.
1847+
*
1848+
* If 0 is returned by the driver's ->fast_switch() callback to indicate an
1849+
* error condition, the hardware configuration must be preserved.
18491850
*/
18501851
unsigned int cpufreq_driver_fast_switch(struct cpufreq_policy *policy,
18511852
unsigned int target_freq)

drivers/cpufreq/cpufreq_governor.c

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -272,6 +272,9 @@ static void dbs_update_util_handler(struct update_util_data *data, u64 time,
272272
struct policy_dbs_info *policy_dbs = cdbs->policy_dbs;
273273
u64 delta_ns, lst;
274274

275+
if (!cpufreq_can_do_remote_dvfs(policy_dbs->policy))
276+
return;
277+
275278
/*
276279
* The work may not be allowed to be queued up right now.
277280
* Possible reasons:

drivers/cpufreq/intel_pstate.c

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1746,6 +1746,10 @@ static void intel_pstate_update_util_pid(struct update_util_data *data,
17461746
struct cpudata *cpu = container_of(data, struct cpudata, update_util);
17471747
u64 delta_ns = time - cpu->sample.time;
17481748

1749+
/* Don't allow remote callbacks */
1750+
if (smp_processor_id() != cpu->cpu)
1751+
return;
1752+
17491753
if ((s64)delta_ns < pid_params.sample_rate_ns)
17501754
return;
17511755

@@ -1763,6 +1767,10 @@ static void intel_pstate_update_util(struct update_util_data *data, u64 time,
17631767
struct cpudata *cpu = container_of(data, struct cpudata, update_util);
17641768
u64 delta_ns;
17651769

1770+
/* Don't allow remote callbacks */
1771+
if (smp_processor_id() != cpu->cpu)
1772+
return;
1773+
17661774
if (flags & SCHED_CPUFREQ_IOWAIT) {
17671775
cpu->iowait_boost = int_tofp(1);
17681776
} else if (cpu->iowait_boost) {

include/linux/cpufreq.h

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -127,6 +127,15 @@ struct cpufreq_policy {
127127
*/
128128
unsigned int transition_delay_us;
129129

130+
/*
131+
* Remote DVFS flag (Not added to the driver structure as we don't want
132+
* to access another structure from scheduler hotpath).
133+
*
134+
* Should be set if CPUs can do DVFS on behalf of other CPUs from
135+
* different cpufreq policies.
136+
*/
137+
bool dvfs_possible_from_any_cpu;
138+
130139
/* Cached frequency lookup from cpufreq_driver_resolve_freq. */
131140
unsigned int cached_target_freq;
132141
int cached_resolved_idx;
@@ -562,6 +571,17 @@ struct governor_attr {
562571
size_t count);
563572
};
564573

574+
static inline bool cpufreq_can_do_remote_dvfs(struct cpufreq_policy *policy)
575+
{
576+
/*
577+
* Allow remote callbacks if:
578+
* - dvfs_possible_from_any_cpu flag is set
579+
* - the local and remote CPUs share cpufreq policy
580+
*/
581+
return policy->dvfs_possible_from_any_cpu ||
582+
cpumask_test_cpu(smp_processor_id(), policy->cpus);
583+
}
584+
565585
/*********************************************************************
566586
* FREQUENCY TABLE HELPERS *
567587
*********************************************************************/

kernel/sched/cpufreq_schedutil.c

Lines changed: 71 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -52,9 +52,11 @@ struct sugov_policy {
5252
struct sugov_cpu {
5353
struct update_util_data update_util;
5454
struct sugov_policy *sg_policy;
55+
unsigned int cpu;
5556

56-
unsigned long iowait_boost;
57-
unsigned long iowait_boost_max;
57+
bool iowait_boost_pending;
58+
unsigned int iowait_boost;
59+
unsigned int iowait_boost_max;
5860
u64 last_update;
5961

6062
/* The fields below are only needed when sharing a policy. */
@@ -76,6 +78,26 @@ static bool sugov_should_update_freq(struct sugov_policy *sg_policy, u64 time)
7678
{
7779
s64 delta_ns;
7880

81+
/*
82+
* Since cpufreq_update_util() is called with rq->lock held for
83+
* the @target_cpu, our per-cpu data is fully serialized.
84+
*
85+
* However, drivers cannot in general deal with cross-cpu
86+
* requests, so while get_next_freq() will work, our
87+
* sugov_update_commit() call may not for the fast switching platforms.
88+
*
89+
* Hence stop here for remote requests if they aren't supported
90+
* by the hardware, as calculating the frequency is pointless if
91+
* we cannot in fact act on it.
92+
*
93+
* For the slow switching platforms, the kthread is always scheduled on
94+
* the right set of CPUs and any CPU can find the next frequency and
95+
* schedule the kthread.
96+
*/
97+
if (sg_policy->policy->fast_switch_enabled &&
98+
!cpufreq_can_do_remote_dvfs(sg_policy->policy))
99+
return false;
100+
79101
if (sg_policy->work_in_progress)
80102
return false;
81103

@@ -106,7 +128,7 @@ static void sugov_update_commit(struct sugov_policy *sg_policy, u64 time,
106128

107129
if (policy->fast_switch_enabled) {
108130
next_freq = cpufreq_driver_fast_switch(policy, next_freq);
109-
if (next_freq == CPUFREQ_ENTRY_INVALID)
131+
if (!next_freq)
110132
return;
111133

112134
policy->cur = next_freq;
@@ -154,12 +176,12 @@ static unsigned int get_next_freq(struct sugov_policy *sg_policy,
154176
return cpufreq_driver_resolve_freq(policy, freq);
155177
}
156178

157-
static void sugov_get_util(unsigned long *util, unsigned long *max)
179+
static void sugov_get_util(unsigned long *util, unsigned long *max, int cpu)
158180
{
159-
struct rq *rq = this_rq();
181+
struct rq *rq = cpu_rq(cpu);
160182
unsigned long cfs_max;
161183

162-
cfs_max = arch_scale_cpu_capacity(NULL, smp_processor_id());
184+
cfs_max = arch_scale_cpu_capacity(NULL, cpu);
163185

164186
*util = min(rq->cfs.avg.util_avg, cfs_max);
165187
*max = cfs_max;
@@ -169,30 +191,54 @@ static void sugov_set_iowait_boost(struct sugov_cpu *sg_cpu, u64 time,
169191
unsigned int flags)
170192
{
171193
if (flags & SCHED_CPUFREQ_IOWAIT) {
172-
sg_cpu->iowait_boost = sg_cpu->iowait_boost_max;
194+
if (sg_cpu->iowait_boost_pending)
195+
return;
196+
197+
sg_cpu->iowait_boost_pending = true;
198+
199+
if (sg_cpu->iowait_boost) {
200+
sg_cpu->iowait_boost <<= 1;
201+
if (sg_cpu->iowait_boost > sg_cpu->iowait_boost_max)
202+
sg_cpu->iowait_boost = sg_cpu->iowait_boost_max;
203+
} else {
204+
sg_cpu->iowait_boost = sg_cpu->sg_policy->policy->min;
205+
}
173206
} else if (sg_cpu->iowait_boost) {
174207
s64 delta_ns = time - sg_cpu->last_update;
175208

176209
/* Clear iowait_boost if the CPU apprears to have been idle. */
177-
if (delta_ns > TICK_NSEC)
210+
if (delta_ns > TICK_NSEC) {
178211
sg_cpu->iowait_boost = 0;
212+
sg_cpu->iowait_boost_pending = false;
213+
}
179214
}
180215
}
181216

182217
static void sugov_iowait_boost(struct sugov_cpu *sg_cpu, unsigned long *util,
183218
unsigned long *max)
184219
{
185-
unsigned long boost_util = sg_cpu->iowait_boost;
186-
unsigned long boost_max = sg_cpu->iowait_boost_max;
220+
unsigned int boost_util, boost_max;
187221

188-
if (!boost_util)
222+
if (!sg_cpu->iowait_boost)
189223
return;
190224

225+
if (sg_cpu->iowait_boost_pending) {
226+
sg_cpu->iowait_boost_pending = false;
227+
} else {
228+
sg_cpu->iowait_boost >>= 1;
229+
if (sg_cpu->iowait_boost < sg_cpu->sg_policy->policy->min) {
230+
sg_cpu->iowait_boost = 0;
231+
return;
232+
}
233+
}
234+
235+
boost_util = sg_cpu->iowait_boost;
236+
boost_max = sg_cpu->iowait_boost_max;
237+
191238
if (*util * boost_max < *max * boost_util) {
192239
*util = boost_util;
193240
*max = boost_max;
194241
}
195-
sg_cpu->iowait_boost >>= 1;
196242
}
197243

198244
#ifdef CONFIG_NO_HZ_COMMON
@@ -229,7 +275,7 @@ static void sugov_update_single(struct update_util_data *hook, u64 time,
229275
if (flags & SCHED_CPUFREQ_RT_DL) {
230276
next_f = policy->cpuinfo.max_freq;
231277
} else {
232-
sugov_get_util(&util, &max);
278+
sugov_get_util(&util, &max, sg_cpu->cpu);
233279
sugov_iowait_boost(sg_cpu, &util, &max);
234280
next_f = get_next_freq(sg_policy, util, max);
235281
/*
@@ -264,6 +310,7 @@ static unsigned int sugov_next_freq_shared(struct sugov_cpu *sg_cpu, u64 time)
264310
delta_ns = time - j_sg_cpu->last_update;
265311
if (delta_ns > TICK_NSEC) {
266312
j_sg_cpu->iowait_boost = 0;
313+
j_sg_cpu->iowait_boost_pending = false;
267314
continue;
268315
}
269316
if (j_sg_cpu->flags & SCHED_CPUFREQ_RT_DL)
@@ -290,7 +337,7 @@ static void sugov_update_shared(struct update_util_data *hook, u64 time,
290337
unsigned long util, max;
291338
unsigned int next_f;
292339

293-
sugov_get_util(&util, &max);
340+
sugov_get_util(&util, &max, sg_cpu->cpu);
294341

295342
raw_spin_lock(&sg_policy->update_lock);
296343

@@ -445,7 +492,11 @@ static int sugov_kthread_create(struct sugov_policy *sg_policy)
445492
}
446493

447494
sg_policy->thread = thread;
448-
kthread_bind_mask(thread, policy->related_cpus);
495+
496+
/* Kthread is bound to all CPUs by default */
497+
if (!policy->dvfs_possible_from_any_cpu)
498+
kthread_bind_mask(thread, policy->related_cpus);
499+
449500
init_irq_work(&sg_policy->irq_work, sugov_irq_work);
450501
mutex_init(&sg_policy->work_lock);
451502

@@ -663,6 +714,11 @@ struct cpufreq_governor *cpufreq_default_governor(void)
663714

664715
static int __init sugov_register(void)
665716
{
717+
int cpu;
718+
719+
for_each_possible_cpu(cpu)
720+
per_cpu(sugov_cpu, cpu).cpu = cpu;
721+
666722
return cpufreq_register_governor(&schedutil_gov);
667723
}
668724
fs_initcall(sugov_register);

kernel/sched/deadline.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1136,7 +1136,7 @@ static void update_curr_dl(struct rq *rq)
11361136
}
11371137

11381138
/* kick cpufreq (see the comment in kernel/sched/sched.h). */
1139-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_DL);
1139+
cpufreq_update_util(rq, SCHED_CPUFREQ_DL);
11401140

11411141
schedstat_set(curr->se.statistics.exec_max,
11421142
max(curr->se.statistics.exec_max, delta_exec));

kernel/sched/fair.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3278,7 +3278,9 @@ static inline void set_tg_cfs_propagate(struct cfs_rq *cfs_rq) {}
32783278

32793279
static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
32803280
{
3281-
if (&this_rq()->cfs == cfs_rq) {
3281+
struct rq *rq = rq_of(cfs_rq);
3282+
3283+
if (&rq->cfs == cfs_rq) {
32823284
/*
32833285
* There are a few boundary cases this might miss but it should
32843286
* get called often enough that that should (hopefully) not be
@@ -3295,7 +3297,7 @@ static inline void cfs_rq_util_change(struct cfs_rq *cfs_rq)
32953297
*
32963298
* See cpu_util().
32973299
*/
3298-
cpufreq_update_util(rq_of(cfs_rq), 0);
3300+
cpufreq_update_util(rq, 0);
32993301
}
33003302
}
33013303

@@ -4875,7 +4877,7 @@ enqueue_task_fair(struct rq *rq, struct task_struct *p, int flags)
48754877
* passed.
48764878
*/
48774879
if (p->in_iowait)
4878-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_IOWAIT);
4880+
cpufreq_update_util(rq, SCHED_CPUFREQ_IOWAIT);
48794881

48804882
for_each_sched_entity(se) {
48814883
if (se->on_rq)

kernel/sched/rt.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -970,7 +970,7 @@ static void update_curr_rt(struct rq *rq)
970970
return;
971971

972972
/* Kick cpufreq (see the comment in kernel/sched/sched.h). */
973-
cpufreq_update_this_cpu(rq, SCHED_CPUFREQ_RT);
973+
cpufreq_update_util(rq, SCHED_CPUFREQ_RT);
974974

975975
schedstat_set(curr->se.statistics.exec_max,
976976
max(curr->se.statistics.exec_max, delta_exec));

kernel/sched/sched.h

Lines changed: 2 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -2070,19 +2070,13 @@ static inline void cpufreq_update_util(struct rq *rq, unsigned int flags)
20702070
{
20712071
struct update_util_data *data;
20722072

2073-
data = rcu_dereference_sched(*this_cpu_ptr(&cpufreq_update_util_data));
2073+
data = rcu_dereference_sched(*per_cpu_ptr(&cpufreq_update_util_data,
2074+
cpu_of(rq)));
20742075
if (data)
20752076
data->func(data, rq_clock(rq), flags);
20762077
}
2077-
2078-
static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags)
2079-
{
2080-
if (cpu_of(rq) == smp_processor_id())
2081-
cpufreq_update_util(rq, flags);
2082-
}
20832078
#else
20842079
static inline void cpufreq_update_util(struct rq *rq, unsigned int flags) {}
2085-
static inline void cpufreq_update_this_cpu(struct rq *rq, unsigned int flags) {}
20862080
#endif /* CONFIG_CPU_FREQ */
20872081

20882082
#ifdef arch_scale_freq_capacity

0 commit comments

Comments
 (0)