Skip to content

Commit dd9f2ae

Browse files
committed
Merge branch 'pm-cpufreq'
* pm-cpufreq: (22 commits) cpufreq: Kconfig: fix documentation links cpufreq: intel_pstate: Simplify intel_pstate_update_perf_limits() cpufreq: armada-37xx: Fix module unloading cpufreq: armada-37xx: Remove cur_frequency variable cpufreq: armada-37xx: Fix determining base CPU frequency cpufreq: armada-37xx: Fix driver cleanup when registration failed clk: mvebu: armada-37xx-periph: Fix workaround for switching from L1 to L0 clk: mvebu: armada-37xx-periph: Fix switching CPU freq from 250 Mhz to 1 GHz cpufreq: armada-37xx: Fix the AVS value for load L1 clk: mvebu: armada-37xx-periph: remove .set_parent method for CPU PM clock cpufreq: armada-37xx: Fix setting TBG parent for load levels cpufreq: Remove unused for_each_policy macro cpufreq: dt: dev_pm_opp_of_cpumask_add_table() may return -EPROBE_DEFER cpufreq: intel_pstate: Clean up frequency computations cpufreq: cppc: simplify default delay_us setting cpufreq: Rudimentary typos fix in the file s5pv210-cpufreq.c cpufreq: CPPC: Add support for frequency invariance ia64: fix format string for ia64-acpi-cpu-freq cpufreq: schedutil: Call sugov_update_next_freq() before check to fast_switch_enabled arch_topology: Export arch_freq_scale and helpers ...
2 parents 71f4dd3 + 733dda9 commit dd9f2ae

16 files changed

Lines changed: 597 additions & 283 deletions

File tree

arch/arm64/include/asm/topology.h

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -17,17 +17,9 @@ int pcibus_to_node(struct pci_bus *bus);
1717
#include <linux/arch_topology.h>
1818

1919
void update_freq_counters_refs(void);
20-
void topology_scale_freq_tick(void);
21-
22-
#ifdef CONFIG_ARM64_AMU_EXTN
23-
/*
24-
* Replace task scheduler's default counter-based
25-
* frequency-invariance scale factor setting.
26-
*/
27-
#define arch_scale_freq_tick topology_scale_freq_tick
28-
#endif /* CONFIG_ARM64_AMU_EXTN */
2920

3021
/* Replace task scheduler's default frequency-invariant accounting */
22+
#define arch_scale_freq_tick topology_scale_freq_tick
3123
#define arch_set_freq_scale topology_set_freq_scale
3224
#define arch_scale_freq_capacity topology_get_freq_scale
3325
#define arch_scale_freq_invariant topology_scale_freq_invariant

arch/arm64/kernel/topology.c

Lines changed: 41 additions & 68 deletions
Original file line numberDiff line numberDiff line change
@@ -199,12 +199,47 @@ static int freq_inv_set_max_ratio(int cpu, u64 max_rate, u64 ref_rate)
199199
return 0;
200200
}
201201

202-
static DEFINE_STATIC_KEY_FALSE(amu_fie_key);
203-
#define amu_freq_invariant() static_branch_unlikely(&amu_fie_key)
202+
static void amu_scale_freq_tick(void)
203+
{
204+
u64 prev_core_cnt, prev_const_cnt;
205+
u64 core_cnt, const_cnt, scale;
206+
207+
prev_const_cnt = this_cpu_read(arch_const_cycles_prev);
208+
prev_core_cnt = this_cpu_read(arch_core_cycles_prev);
209+
210+
update_freq_counters_refs();
211+
212+
const_cnt = this_cpu_read(arch_const_cycles_prev);
213+
core_cnt = this_cpu_read(arch_core_cycles_prev);
214+
215+
if (unlikely(core_cnt <= prev_core_cnt ||
216+
const_cnt <= prev_const_cnt))
217+
return;
218+
219+
/*
220+
* /\core arch_max_freq_scale
221+
* scale = ------- * --------------------
222+
* /\const SCHED_CAPACITY_SCALE
223+
*
224+
* See validate_cpu_freq_invariance_counters() for details on
225+
* arch_max_freq_scale and the use of SCHED_CAPACITY_SHIFT.
226+
*/
227+
scale = core_cnt - prev_core_cnt;
228+
scale *= this_cpu_read(arch_max_freq_scale);
229+
scale = div64_u64(scale >> SCHED_CAPACITY_SHIFT,
230+
const_cnt - prev_const_cnt);
231+
232+
scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE);
233+
this_cpu_write(arch_freq_scale, (unsigned long)scale);
234+
}
235+
236+
static struct scale_freq_data amu_sfd = {
237+
.source = SCALE_FREQ_SOURCE_ARCH,
238+
.set_freq_scale = amu_scale_freq_tick,
239+
};
204240

205241
static void amu_fie_setup(const struct cpumask *cpus)
206242
{
207-
bool invariant;
208243
int cpu;
209244

210245
/* We are already set since the last insmod of cpufreq driver */
@@ -221,25 +256,10 @@ static void amu_fie_setup(const struct cpumask *cpus)
221256

222257
cpumask_or(amu_fie_cpus, amu_fie_cpus, cpus);
223258

224-
invariant = topology_scale_freq_invariant();
225-
226-
/* We aren't fully invariant yet */
227-
if (!invariant && !cpumask_equal(amu_fie_cpus, cpu_present_mask))
228-
return;
229-
230-
static_branch_enable(&amu_fie_key);
259+
topology_set_scale_freq_source(&amu_sfd, amu_fie_cpus);
231260

232261
pr_debug("CPUs[%*pbl]: counters will be used for FIE.",
233262
cpumask_pr_args(cpus));
234-
235-
/*
236-
* Task scheduler behavior depends on frequency invariance support,
237-
* either cpufreq or counter driven. If the support status changes as
238-
* a result of counter initialisation and use, retrigger the build of
239-
* scheduling domains to ensure the information is propagated properly.
240-
*/
241-
if (!invariant)
242-
rebuild_sched_domains_energy();
243263
}
244264

245265
static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
@@ -256,8 +276,8 @@ static int init_amu_fie_callback(struct notifier_block *nb, unsigned long val,
256276
* initialized AMU support and enabled invariance. The AMU counters will
257277
* keep on working just fine in the absence of the cpufreq driver, and
258278
* for the CPUs for which there are no counters available, the last set
259-
* value of freq_scale will remain valid as that is the frequency those
260-
* CPUs are running at.
279+
* value of arch_freq_scale will remain valid as that is the frequency
280+
* those CPUs are running at.
261281
*/
262282

263283
return 0;
@@ -283,53 +303,6 @@ static int __init init_amu_fie(void)
283303
}
284304
core_initcall(init_amu_fie);
285305

286-
bool arch_freq_counters_available(const struct cpumask *cpus)
287-
{
288-
return amu_freq_invariant() &&
289-
cpumask_subset(cpus, amu_fie_cpus);
290-
}
291-
292-
void topology_scale_freq_tick(void)
293-
{
294-
u64 prev_core_cnt, prev_const_cnt;
295-
u64 core_cnt, const_cnt, scale;
296-
int cpu = smp_processor_id();
297-
298-
if (!amu_freq_invariant())
299-
return;
300-
301-
if (!cpumask_test_cpu(cpu, amu_fie_cpus))
302-
return;
303-
304-
prev_const_cnt = this_cpu_read(arch_const_cycles_prev);
305-
prev_core_cnt = this_cpu_read(arch_core_cycles_prev);
306-
307-
update_freq_counters_refs();
308-
309-
const_cnt = this_cpu_read(arch_const_cycles_prev);
310-
core_cnt = this_cpu_read(arch_core_cycles_prev);
311-
312-
if (unlikely(core_cnt <= prev_core_cnt ||
313-
const_cnt <= prev_const_cnt))
314-
return;
315-
316-
/*
317-
* /\core arch_max_freq_scale
318-
* scale = ------- * --------------------
319-
* /\const SCHED_CAPACITY_SCALE
320-
*
321-
* See validate_cpu_freq_invariance_counters() for details on
322-
* arch_max_freq_scale and the use of SCHED_CAPACITY_SHIFT.
323-
*/
324-
scale = core_cnt - prev_core_cnt;
325-
scale *= this_cpu_read(arch_max_freq_scale);
326-
scale = div64_u64(scale >> SCHED_CAPACITY_SHIFT,
327-
const_cnt - prev_const_cnt);
328-
329-
scale = min_t(unsigned long, scale, SCHED_CAPACITY_SCALE);
330-
this_cpu_write(freq_scale, (unsigned long)scale);
331-
}
332-
333306
#ifdef CONFIG_ACPI_CPPC_LIB
334307
#include <acpi/cppc_acpi.h>
335308

drivers/base/arch_topology.c

Lines changed: 83 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -21,17 +21,94 @@
2121
#include <linux/sched.h>
2222
#include <linux/smp.h>
2323

24+
static DEFINE_PER_CPU(struct scale_freq_data *, sft_data);
25+
static struct cpumask scale_freq_counters_mask;
26+
static bool scale_freq_invariant;
27+
28+
static bool supports_scale_freq_counters(const struct cpumask *cpus)
29+
{
30+
return cpumask_subset(cpus, &scale_freq_counters_mask);
31+
}
32+
2433
bool topology_scale_freq_invariant(void)
2534
{
2635
return cpufreq_supports_freq_invariance() ||
27-
arch_freq_counters_available(cpu_online_mask);
36+
supports_scale_freq_counters(cpu_online_mask);
2837
}
2938

30-
__weak bool arch_freq_counters_available(const struct cpumask *cpus)
39+
static void update_scale_freq_invariant(bool status)
3140
{
32-
return false;
41+
if (scale_freq_invariant == status)
42+
return;
43+
44+
/*
45+
* Task scheduler behavior depends on frequency invariance support,
46+
* either cpufreq or counter driven. If the support status changes as
47+
* a result of counter initialisation and use, retrigger the build of
48+
* scheduling domains to ensure the information is propagated properly.
49+
*/
50+
if (topology_scale_freq_invariant() == status) {
51+
scale_freq_invariant = status;
52+
rebuild_sched_domains_energy();
53+
}
3354
}
34-
DEFINE_PER_CPU(unsigned long, freq_scale) = SCHED_CAPACITY_SCALE;
55+
56+
void topology_set_scale_freq_source(struct scale_freq_data *data,
57+
const struct cpumask *cpus)
58+
{
59+
struct scale_freq_data *sfd;
60+
int cpu;
61+
62+
/*
63+
* Avoid calling rebuild_sched_domains() unnecessarily if FIE is
64+
* supported by cpufreq.
65+
*/
66+
if (cpumask_empty(&scale_freq_counters_mask))
67+
scale_freq_invariant = topology_scale_freq_invariant();
68+
69+
for_each_cpu(cpu, cpus) {
70+
sfd = per_cpu(sft_data, cpu);
71+
72+
/* Use ARCH provided counters whenever possible */
73+
if (!sfd || sfd->source != SCALE_FREQ_SOURCE_ARCH) {
74+
per_cpu(sft_data, cpu) = data;
75+
cpumask_set_cpu(cpu, &scale_freq_counters_mask);
76+
}
77+
}
78+
79+
update_scale_freq_invariant(true);
80+
}
81+
EXPORT_SYMBOL_GPL(topology_set_scale_freq_source);
82+
83+
void topology_clear_scale_freq_source(enum scale_freq_source source,
84+
const struct cpumask *cpus)
85+
{
86+
struct scale_freq_data *sfd;
87+
int cpu;
88+
89+
for_each_cpu(cpu, cpus) {
90+
sfd = per_cpu(sft_data, cpu);
91+
92+
if (sfd && sfd->source == source) {
93+
per_cpu(sft_data, cpu) = NULL;
94+
cpumask_clear_cpu(cpu, &scale_freq_counters_mask);
95+
}
96+
}
97+
98+
update_scale_freq_invariant(false);
99+
}
100+
EXPORT_SYMBOL_GPL(topology_clear_scale_freq_source);
101+
102+
void topology_scale_freq_tick(void)
103+
{
104+
struct scale_freq_data *sfd = *this_cpu_ptr(&sft_data);
105+
106+
if (sfd)
107+
sfd->set_freq_scale();
108+
}
109+
110+
DEFINE_PER_CPU(unsigned long, arch_freq_scale) = SCHED_CAPACITY_SCALE;
111+
EXPORT_PER_CPU_SYMBOL_GPL(arch_freq_scale);
35112

36113
void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
37114
unsigned long max_freq)
@@ -47,13 +124,13 @@ void topology_set_freq_scale(const struct cpumask *cpus, unsigned long cur_freq,
47124
* want to update the scale factor with information from CPUFREQ.
48125
* Instead the scale factor will be updated from arch_scale_freq_tick.
49126
*/
50-
if (arch_freq_counters_available(cpus))
127+
if (supports_scale_freq_counters(cpus))
51128
return;
52129

53130
scale = (cur_freq << SCHED_CAPACITY_SHIFT) / max_freq;
54131

55132
for_each_cpu(i, cpus)
56-
per_cpu(freq_scale, i) = scale;
133+
per_cpu(arch_freq_scale, i) = scale;
57134
}
58135

59136
DEFINE_PER_CPU(unsigned long, cpu_scale) = SCHED_CAPACITY_SCALE;

0 commit comments

Comments
 (0)