[PATCH v1] arch_topology: Adjust initial CPU capacities with current freq

From: Jeffy Chen
Date: Thu Jan 09 2020 - 03:00:11 EST


The CPU freqs are not supposed to change before cpufreq policies
properly registered, meaning that they should be used to calculate the
initial CPU capacities.

Doing this helps choosing the best CPU during early boot, especially
for the initramfs decompressing.

Signed-off-by: Jeffy Chen <jeffy.chen@xxxxxxxxxxxxxx>
---
When testing the rk3399-evb(arm64 big.LITTLE platform), i saw a noticable
slow-down in early boot:
[ 0.280176] hw-breakpoint: found 6 breakpoint and 4 watchpoint registers.
[ 3.564412] vcc_sys: supplied by dc_12v
[ 3.637176] iommu: Default domain type: Translated
[ 3.830721] SCSI subsystem initialized

That is because the big cores are running at a low freq(from bootrom), but
been chosen based on the larger initial cpu capacity.

drivers/base/arch_topology.c | 31 ++++++++++++++++++++-----------
1 file changed, 20 insertions(+), 11 deletions(-)

diff --git a/drivers/base/arch_topology.c b/drivers/base/arch_topology.c
index 1eb81f113786..d62fe1d4dda9 100644
--- a/drivers/base/arch_topology.c
+++ b/drivers/base/arch_topology.c
@@ -94,7 +94,7 @@ static void update_topology_flags_workfn(struct work_struct *work)
update_topology = 0;
}

-static u32 capacity_scale;
+static DEFINE_PER_CPU(u32, max_freq);
static u32 *raw_capacity;

static int free_raw_capacity(void)
@@ -108,16 +108,22 @@ static int free_raw_capacity(void)
void topology_normalize_cpu_scale(void)
{
u64 capacity;
+ u64 capacity_scale;
int cpu;

if (!raw_capacity)
return;

- pr_debug("cpu_capacity: capacity_scale=%u\n", capacity_scale);
+ capacity_scale = 1;
for_each_possible_cpu(cpu) {
- pr_debug("cpu_capacity: cpu=%d raw_capacity=%u\n",
- cpu, raw_capacity[cpu]);
- capacity = (raw_capacity[cpu] << SCHED_CAPACITY_SHIFT)
+ capacity = raw_capacity[cpu] * per_cpu(max_freq, cpu);
+ capacity_scale = max(capacity, capacity_scale);
+ }
+
+ pr_debug("cpu_capacity: capacity_scale=%llu\n", capacity_scale);
+ for_each_possible_cpu(cpu) {
+ capacity = raw_capacity[cpu] * per_cpu(max_freq, cpu);
+ capacity = (capacity << SCHED_CAPACITY_SHIFT)
/ capacity_scale;
topology_set_cpu_scale(cpu, capacity);
pr_debug("cpu_capacity: CPU%d cpu_capacity=%lu\n",
@@ -127,6 +133,7 @@ void topology_normalize_cpu_scale(void)

bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
{
+ struct clk *cpu_clk;
static bool cap_parsing_failed;
int ret;
u32 cpu_capacity;
@@ -146,10 +153,15 @@ bool __init topology_parse_cpu_capacity(struct device_node *cpu_node, int cpu)
return false;
}
}
- capacity_scale = max(cpu_capacity, capacity_scale);
raw_capacity[cpu] = cpu_capacity;
pr_debug("cpu_capacity: %pOF cpu_capacity=%u (raw)\n",
cpu_node, raw_capacity[cpu]);
+
+ cpu_clk = of_clk_get(cpu_node, 0);
+ if (!PTR_ERR_OR_ZERO(cpu_clk))
+ per_cpu(max_freq, cpu) = clk_get_rate(cpu_clk) / 1000;
+
+ clk_put(cpu_clk);
} else {
if (raw_capacity) {
pr_err("cpu_capacity: missing %pOF raw capacity\n",
@@ -188,11 +200,8 @@ init_cpu_capacity_callback(struct notifier_block *nb,

cpumask_andnot(cpus_to_visit, cpus_to_visit, policy->related_cpus);

- for_each_cpu(cpu, policy->related_cpus) {
- raw_capacity[cpu] = topology_get_cpu_scale(cpu) *
- policy->cpuinfo.max_freq / 1000UL;
- capacity_scale = max(raw_capacity[cpu], capacity_scale);
- }
+ for_each_cpu(cpu, policy->related_cpus)
+ per_cpu(max_freq, cpu) = policy->cpuinfo.max_freq / 1000;

if (cpumask_empty(cpus_to_visit)) {
topology_normalize_cpu_scale();
--
2.11.0