Commit 0b587c84 authored by Suzuki K Poulose's avatar Suzuki K Poulose Committed by Will Deacon

arm64: capabilities: Batch cpu_enable callbacks

We use a stop_machine call for each available capability to
enable it on all the CPUs available at boot time. Instead
we could batch the cpu_enable callbacks to a single stop_machine()
call to save us some time.
Reviewed-by: default avatarVladimir Murzin <vladimir.murzin@arm.com>
Tested-by: default avatarVladimir Murzin <vladimir.murzin@arm.com>
Signed-off-by: default avatarSuzuki K Poulose <suzuki.poulose@arm.com>
Signed-off-by: default avatarWill Deacon <will.deacon@arm.com>
parent 606f8e7b
...@@ -357,6 +357,9 @@ extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS); ...@@ -357,6 +357,9 @@ extern DECLARE_BITMAP(cpu_hwcaps, ARM64_NCAPS);
extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS]; extern struct static_key_false cpu_hwcap_keys[ARM64_NCAPS];
extern struct static_key_false arm64_const_caps_ready; extern struct static_key_false arm64_const_caps_ready;
#define for_each_available_cap(cap) \
for_each_set_bit(cap, cpu_hwcaps, ARM64_NCAPS)
bool this_cpu_has_cap(unsigned int cap); bool this_cpu_has_cap(unsigned int cap);
static inline bool cpu_have_feature(unsigned int num) static inline bool cpu_have_feature(unsigned int num)
......
...@@ -1531,11 +1531,27 @@ static void update_cpu_capabilities(u16 scope_mask) ...@@ -1531,11 +1531,27 @@ static void update_cpu_capabilities(u16 scope_mask)
} }
} }
static int __enable_cpu_capability(void *arg) /*
* Enable all the available capabilities on this CPU. The capabilities
* with BOOT_CPU scope are handled separately and hence skipped here.
*/
static int cpu_enable_non_boot_scope_capabilities(void *__unused)
{ {
const struct arm64_cpu_capabilities *cap = arg; int i;
u16 non_boot_scope = SCOPE_ALL & ~SCOPE_BOOT_CPU;
for_each_available_cap(i) {
const struct arm64_cpu_capabilities *cap = cpu_hwcaps_ptrs[i];
if (WARN_ON(!cap))
continue;
if (!(cap->type & non_boot_scope))
continue;
cap->cpu_enable(cap); if (cap->cpu_enable)
cap->cpu_enable(cap);
}
return 0; return 0;
} }
...@@ -1543,21 +1559,29 @@ static int __enable_cpu_capability(void *arg) ...@@ -1543,21 +1559,29 @@ static int __enable_cpu_capability(void *arg)
* Run through the enabled capabilities and enable() it on all active * Run through the enabled capabilities and enable() it on all active
* CPUs * CPUs
*/ */
static void __init static void __init enable_cpu_capabilities(u16 scope_mask)
__enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
u16 scope_mask)
{ {
int i;
const struct arm64_cpu_capabilities *caps;
bool boot_scope;
scope_mask &= ARM64_CPUCAP_SCOPE_MASK; scope_mask &= ARM64_CPUCAP_SCOPE_MASK;
for (; caps->matches; caps++) { boot_scope = !!(scope_mask & SCOPE_BOOT_CPU);
unsigned int num = caps->capability;
for (i = 0; i < ARM64_NCAPS; i++) {
unsigned int num;
if (!(caps->type & scope_mask) || !cpus_have_cap(num)) caps = cpu_hwcaps_ptrs[i];
if (!caps || !(caps->type & scope_mask))
continue;
num = caps->capability;
if (!cpus_have_cap(num))
continue; continue;
/* Ensure cpus_have_const_cap(num) works */ /* Ensure cpus_have_const_cap(num) works */
static_branch_enable(&cpu_hwcap_keys[num]); static_branch_enable(&cpu_hwcap_keys[num]);
if (caps->cpu_enable) { if (boot_scope && caps->cpu_enable)
/* /*
* Capabilities with SCOPE_BOOT_CPU scope are finalised * Capabilities with SCOPE_BOOT_CPU scope are finalised
* before any secondary CPU boots. Thus, each secondary * before any secondary CPU boots. Thus, each secondary
...@@ -1566,25 +1590,19 @@ __enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps, ...@@ -1566,25 +1590,19 @@ __enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
* the boot CPU, for which the capability must be * the boot CPU, for which the capability must be
* enabled here. This approach avoids costly * enabled here. This approach avoids costly
* stop_machine() calls for this case. * stop_machine() calls for this case.
*
* Otherwise, use stop_machine() as it schedules the
* work allowing us to modify PSTATE, instead of
* on_each_cpu() which uses an IPI, giving us a PSTATE
* that disappears when we return.
*/ */
if (scope_mask & SCOPE_BOOT_CPU) caps->cpu_enable(caps);
caps->cpu_enable(caps);
else
stop_machine(__enable_cpu_capability,
(void *)caps, cpu_online_mask);
}
} }
}
static void __init enable_cpu_capabilities(u16 scope_mask) /*
{ * For all non-boot scope capabilities, use stop_machine()
__enable_cpu_capabilities(arm64_errata, scope_mask); * as it schedules the work allowing us to modify PSTATE,
__enable_cpu_capabilities(arm64_features, scope_mask); * instead of on_each_cpu() which uses an IPI, giving us a
* PSTATE that disappears when we return.
*/
if (!boot_scope)
stop_machine(cpu_enable_non_boot_scope_capabilities,
NULL, cpu_online_mask);
} }
/* /*
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment