[PATCH v2 0/2] arm64: Run enable method for errata work arounds on late CPUs
Robin Murphy
robin.murphy at arm.com
Thu Jan 18 04:00:07 PST 2018
On 18/01/18 11:45, Dave Martin wrote:
> On Wed, Jan 17, 2018 at 05:42:19PM +0000, Suzuki K Poulose wrote:
>> We issue the enable() call back for all CPU hwcaps capabilities
>> available on the system, on all the CPUs. So far we have ignored
>> the argument passed to the call back, which had a prototype to
>> accept a "void *" for use with on_each_cpu() and later with
>> stop_machine(). However, with commit 0a0d111d40fd1
>> ("arm64: cpufeature: Pass capability structure to ->enable callback"),
>> there are some users of the argument who wants the matching capability
>> struct pointer where there are multiple matching criteria for a single
>> capability. Changing the prototype is quite an invasive change and
>
> It's not that bad, though it's debatable whether it's really worth
> it. See the appended patch below.
>
>> will be part of a future series. For now, add a comment to clarify
>> what is expected.
>
> With the type change, it becomes more obvious what should be passed,
> and the comment can probably be trimmed down. I omit the comment
> from my patch (I'm lazy).
>
> Without it, I would prefer a comment alongside the (void *) cast,
> something like "enable methods expect this to be passed as a void *,
> for compatibility with stop_machine()".
>
> For consistency, the stop_machine() call should also be changed to
> pass the cap pointer instead of NULL, even if we don't actually rely
> on that for any purpose today -- it will help avoid surprises in the
> future. (My patch does makes an equivalent change.)
>
> [...]
>
>> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
>> index ac67cfc2585a..c049e28274d4 100644
>> --- a/arch/arm64/include/asm/cpufeature.h
>> +++ b/arch/arm64/include/asm/cpufeature.h
>> @@ -97,7 +97,14 @@ struct arm64_cpu_capabilities {
>> u16 capability;
>> int def_scope; /* default scope */
>> bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
>> - int (*enable)(void *); /* Called on all active CPUs */
>> + /*
>> + * For each @capability set in CPU hwcaps, @enable() is called on all
>> + * active CPUs with const struct arm64_cpu_capabilities * as argument.
>
> The declaration tells us the type, so we don't need that in the comment.
> But what object should the pointer point to?
>
>> + * It is upto the callback (especially when multiple entries for the
>
> up to
>
>> + * same capability exists) to determine if any action should be taken
>> + * based on @matches() applies to thie CPU.
>> + */
>> + int (*enable)(void *caps);
>> union {
>> struct { /* To be used for erratum handling only */
>> u32 midr_model;
>
> Cheers
> ---Dave
>
>
> --8<--
>
> From 04a4bd998d02e339341db250e66b0d34a7c4e042 Mon Sep 17 00:00:00 2001
> From: Dave Martin <Dave.Martin at arm.com>
> Date: Thu, 18 Jan 2018 11:29:14 +0000
> Subject: [PATCH] arm64: cpufeature: Formalise capability enable method type
>
> Currently, all cpufeature enable methods specify their argument as
> a void *, while what is actually passed is a pointer to a const
> struct arm64_cpu_capabilities object.
>
> Hiding the type information from the compiler increases the risk
> of incorrect code.
>
> Instead of requiring care to be taken in every enable method, this
> patch makes the type of the argument explicitly struct
> arm64_cpu_capabilities const *.
>
> Since we need to call these methods via stop_machine(), a single
> proxy function __cpu_enable_capability() is added which is passed
> to stop_machine() to allow it to call feature enable methods
> without defeating type checking in the compiler (except in this
> one place).
>
> This patch should not change the behaviour of the kernel.
>
> Signed-off-by: Dave Martin <Dave.Martin at arm.com>
>
> ---
>
> Build-tested only.
>
> arch/arm64/include/asm/cpufeature.h | 4 +++-
> arch/arm64/include/asm/fpsimd.h | 4 +++-
> arch/arm64/include/asm/processor.h | 5 +++--
> arch/arm64/kernel/cpu_errata.c | 3 ++-
> arch/arm64/kernel/cpufeature.c | 20 +++++++++++++++++++-
> arch/arm64/kernel/fpsimd.c | 3 ++-
> arch/arm64/kernel/traps.c | 3 ++-
> arch/arm64/mm/fault.c | 2 +-
> 8 files changed, 35 insertions(+), 9 deletions(-)
>
> diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
> index 060e3a4..98d22ce 100644
> --- a/arch/arm64/include/asm/cpufeature.h
> +++ b/arch/arm64/include/asm/cpufeature.h
> @@ -100,7 +100,9 @@ struct arm64_cpu_capabilities {
> u16 capability;
> int def_scope; /* default scope */
> bool (*matches)(const struct arm64_cpu_capabilities *caps, int scope);
> - int (*enable)(void *); /* Called on all active CPUs */
> + /* Called on all active CPUs: */
> + int (*enable)(struct arm64_cpu_capabilities const *);
> +
> union {
> struct { /* To be used for erratum handling only */
> u32 midr_model;
> diff --git a/arch/arm64/include/asm/fpsimd.h b/arch/arm64/include/asm/fpsimd.h
> index 74f3439..ac9902d 100644
> --- a/arch/arm64/include/asm/fpsimd.h
> +++ b/arch/arm64/include/asm/fpsimd.h
> @@ -83,7 +83,9 @@ extern void sve_save_state(void *state, u32 *pfpsr);
> extern void sve_load_state(void const *state, u32 const *pfpsr,
> unsigned long vq_minus_1);
> extern unsigned int sve_get_vl(void);
> -extern int sve_kernel_enable(void *);
> +
> +struct arm64_cpu_capabilities;
> +extern int sve_kernel_enable(struct arm64_cpu_capabilities const *);
>
> extern int __ro_after_init sve_max_vl;
>
> diff --git a/arch/arm64/include/asm/processor.h b/arch/arm64/include/asm/processor.h
> index 023cacb..46959651a 100644
> --- a/arch/arm64/include/asm/processor.h
> +++ b/arch/arm64/include/asm/processor.h
> @@ -34,6 +34,7 @@
> #include <linux/string.h>
>
> #include <asm/alternative.h>
> +#include <asm/cpufeature.h>
> #include <asm/fpsimd.h>
> #include <asm/hw_breakpoint.h>
> #include <asm/lse.h>
> @@ -214,8 +215,8 @@ static inline void spin_lock_prefetch(const void *ptr)
>
> #endif
>
> -int cpu_enable_pan(void *__unused);
> -int cpu_enable_cache_maint_trap(void *__unused);
> +int cpu_enable_pan(struct arm64_cpu_capabilities const *__unused);
> +int cpu_enable_cache_maint_trap(struct arm64_cpu_capabilities const *__unused);
>
> /* Userspace interface for PR_SVE_{SET,GET}_VL prctl()s: */
> #define SVE_SET_VL(arg) sve_set_current_vl(arg)
> diff --git a/arch/arm64/kernel/cpu_errata.c b/arch/arm64/kernel/cpu_errata.c
> index 0e27f86..addd7fd 100644
> --- a/arch/arm64/kernel/cpu_errata.c
> +++ b/arch/arm64/kernel/cpu_errata.c
> @@ -39,7 +39,8 @@ has_mismatched_cache_line_size(const struct arm64_cpu_capabilities *entry,
> (arm64_ftr_reg_ctrel0.sys_val & arm64_ftr_reg_ctrel0.strict_mask);
> }
>
> -static int cpu_enable_trap_ctr_access(void *__unused)
> +static int cpu_enable_trap_ctr_access(
> + struct arm64_cpu_capabilities const *__unused)
> {
> /* Clear SCTLR_EL1.UCT */
> config_sctlr_el1(SCTLR_EL1_UCT, 0);
> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index a73a592..05486a9 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -1084,6 +1084,18 @@ void update_cpu_capabilities(const struct arm64_cpu_capabilities *caps,
> }
> }
>
> +struct enable_arg {
> + int (*enable)(struct arm64_cpu_capabilities const *);
> + struct arm64_cpu_capabilities const *cap;
> +};
> +
> +static int __enable_cpu_capability(void *arg)
> +{
> + struct enable_arg const *e = arg;
> +
> + return e->enable(e->cap);
> +}
AFAICS, you shouldn't even need the intermediate struct - if you were
instead to call stop_machine(&caps->enable, ...), the wrapper could be:
<type> **fn = arg;
*fn(container_of(fn, struct arm64_cpu_capabilities, enable));
(cheaty pseudocode because there's no way I'm going to write a
pointer-to-function-pointer type correctly in an email client...)
That's certainly a fair bit simpler in terms of diffstat; whether it's
really as intuitive as I think it is is perhaps another matter, though.
Robin.
> +
> /*
> * Run through the enabled capabilities and enable() it on all active
> * CPUs
> @@ -1100,13 +1112,19 @@ void __init enable_cpu_capabilities(const struct arm64_cpu_capabilities *caps)
> static_branch_enable(&cpu_hwcap_keys[num]);
>
> if (caps->enable) {
> + struct enable_arg e = {
> + .enable = caps->enable,
> + .cap = caps,
> + };
> +
> /*
> * 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.
> */
> - stop_machine(caps->enable, NULL, cpu_online_mask);
> + stop_machine(__enable_cpu_capability, &e,
> + cpu_online_mask);
> }
> }
> }
> diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c
> index fae81f7..b6dcfa3 100644
> --- a/arch/arm64/kernel/fpsimd.c
> +++ b/arch/arm64/kernel/fpsimd.c
> @@ -40,6 +40,7 @@
> #include <linux/sysctl.h>
>
> #include <asm/fpsimd.h>
> +#include <asm/cpufeature.h>
> #include <asm/cputype.h>
> #include <asm/simd.h>
> #include <asm/sigcontext.h>
> @@ -757,7 +758,7 @@ static void __init sve_efi_setup(void)
> * Enable SVE for EL1.
> * Intended for use by the cpufeatures code during CPU boot.
> */
> -int sve_kernel_enable(void *__always_unused p)
> +int sve_kernel_enable(struct arm64_cpu_capabilities const *__always_unused p)
> {
> write_sysreg(read_sysreg(CPACR_EL1) | CPACR_EL1_ZEN_EL1EN, CPACR_EL1);
> isb();
> diff --git a/arch/arm64/kernel/traps.c b/arch/arm64/kernel/traps.c
> index 3d3588f..2457514 100644
> --- a/arch/arm64/kernel/traps.c
> +++ b/arch/arm64/kernel/traps.c
> @@ -38,6 +38,7 @@
>
> #include <asm/atomic.h>
> #include <asm/bug.h>
> +#include <asm/cpufeature.h>
> #include <asm/daifflags.h>
> #include <asm/debug-monitors.h>
> #include <asm/esr.h>
> @@ -374,7 +375,7 @@ asmlinkage void __exception do_undefinstr(struct pt_regs *regs)
> force_signal_inject(SIGILL, ILL_ILLOPC, regs, 0);
> }
>
> -int cpu_enable_cache_maint_trap(void *__unused)
> +int cpu_enable_cache_maint_trap(struct arm64_cpu_capabilities const *__unused)
> {
> config_sctlr_el1(SCTLR_EL1_UCI, 0);
> return 0;
> diff --git a/arch/arm64/mm/fault.c b/arch/arm64/mm/fault.c
> index 9b7f89d..82f6729 100644
> --- a/arch/arm64/mm/fault.c
> +++ b/arch/arm64/mm/fault.c
> @@ -795,7 +795,7 @@ asmlinkage int __exception do_debug_exception(unsigned long addr,
> NOKPROBE_SYMBOL(do_debug_exception);
>
> #ifdef CONFIG_ARM64_PAN
> -int cpu_enable_pan(void *__unused)
> +int cpu_enable_pan(struct arm64_cpu_capabilities const *__unused)
> {
> /*
> * We modify PSTATE. This won't work from irq context as the PSTATE
>
More information about the linux-arm-kernel
mailing list