Message ID | 1549459868-45992-3-git-send-email-andrew.murray@arm.com (mailing list archive) |
---|---|
State | New, archived |
Headers | show |
Series | Initial support for CVADP | expand |
On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote: > As we will exhaust the first 32 bits of ELF_HWCAP let's start > exposing ELF_HWCAP2 to userspace. > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we > prefer to expand into ELF_HWCAP2 in order to provide a consistent > view to userspace between ILP32 and LP64. > > To reduce complexity and allow for future expansion, we now > represent hwcaps in the kernel as ordinals and use a > KERNEL_HWCAP_ prefix. This allows us to support automatic feature > based module loading for all our hwcaps. > > We introduce cpu_set_feature to set hwcaps in the relevant > elf_hwcapX variable which compliments the existing cpu_have_feature > helper. These helpers allow us to clean up existing direct uses of > elf_hwcap. > > Signed-off-by: Andrew Murray <andrew.murray@arm.com> > --- [...] > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > index dfcfba7..15d939e 100644 > --- a/arch/arm64/include/asm/cpufeature.h > +++ b/arch/arm64/include/asm/cpufeature.h > @@ -18,11 +18,10 @@ > * In the arm64 world (as in the ARM world), elf_hwcap is used both internally > * in the kernel and for user space to keep track of which optional features > * are supported by the current system. So let's map feature 'x' to HWCAP_x. > - * Note that HWCAP_x constants are bit fields so we need to take the log. > */ > > -#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) > -#define cpu_feature(x) ilog2(HWCAP_ ## x) > +#define MAX_CPU_FEATURES (2 * 8 * sizeof(unsigned long)) Doesn't this make 2 * 8 * 8 == 128? Maybe just say "64". We open-code 32 later anyway. > +#define cpu_feature(x) (KERNEL_HWCAP_ ## x) > > #ifndef __ASSEMBLY__ > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready; > > bool this_cpu_has_cap(unsigned int cap); > > +static inline void cpu_set_feature(unsigned int num) > +{ > + if (num < 32) > + elf_hwcap |= BIT(num); > + else > + elf_hwcap2 |= BIT(num - 32); > +} > + > static inline bool cpu_have_feature(unsigned int num) > { > - return elf_hwcap & (1UL << num); > + if (num < 32) > + return elf_hwcap & BIT(num); > + else > + return elf_hwcap2 & BIT(num - 32); > } Nit: I worry a bit that people will blithely pass HWCAP_foo to these, not realising that the interface has changed. Can we do something like the following: static inline bool __cpu_have_feature(unsigned int num) { if (WARN_ON(num >= 64)) return false; if (num < 32) return elf_hwcap & BIT(num); else return elf_hwcap2 & BIT(num); } #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name)) In compiletime-constant cases, the compiler should simply delete the WARN. A couple of cases in the cpufeatures and /proc/cpuinfo code would need to use __cpu_have_feature directly and would retain the WARN, but that's not fastpath and probably not the end of the world, plus we get an additional debugging aid if that code goes wrong. Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making it impossible to specify invalid or user-encoded hwcaps there either. Then we might justifiably omit the policing in __cpu_have_feature() altogether. > > /* System capability check for constant caps */ > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h > index 400b80b..05ee9b9 100644 > --- a/arch/arm64/include/asm/hwcap.h > +++ b/arch/arm64/include/asm/hwcap.h > @@ -39,12 +39,49 @@ > #define COMPAT_HWCAP2_SHA2 (1 << 3) > #define COMPAT_HWCAP2_CRC32 (1 << 4) > > +/* > + * KERNEL_HWCAP flags - for elf_hwcap (in kernel) > + */ > +#define KERNEL_HWCAP_FP ilog2(HWCAP_FP) > +#define KERNEL_HWCAP_ASIMD ilog2(HWCAP_ASIMD) > +#define KERNEL_HWCAP_EVTSTRM ilog2(HWCAP_EVTSTRM) > +#define KERNEL_HWCAP_AES ilog2(HWCAP_AES) > +#define KERNEL_HWCAP_PMULL ilog2(HWCAP_PMULL) > +#define KERNEL_HWCAP_SHA1 ilog2(HWCAP_SHA1) > +#define KERNEL_HWCAP_SHA2 ilog2(HWCAP_SHA2) > +#define KERNEL_HWCAP_CRC32 ilog2(HWCAP_CRC32) > +#define KERNEL_HWCAP_ATOMICS ilog2(HWCAP_ATOMICS) > +#define KERNEL_HWCAP_FPHP ilog2(HWCAP_FPHP) > +#define KERNEL_HWCAP_ASIMDHP ilog2(HWCAP_ASIMDHP) > +#define KERNEL_HWCAP_CPUID ilog2(HWCAP_CPUID) > +#define KERNEL_HWCAP_ASIMDRDM ilog2(HWCAP_ASIMDRDM) > +#define KERNEL_HWCAP_JSCVT ilog2(HWCAP_JSCVT) > +#define KERNEL_HWCAP_FCMA ilog2(HWCAP_FCMA) > +#define KERNEL_HWCAP_LRCPC ilog2(HWCAP_LRCPC) > +#define KERNEL_HWCAP_DCPOP ilog2(HWCAP_DCPOP) > +#define KERNEL_HWCAP_SHA3 ilog2(HWCAP_SHA3) > +#define KERNEL_HWCAP_SM3 ilog2(HWCAP_SM3) > +#define KERNEL_HWCAP_SM4 ilog2(HWCAP_SM4) > +#define KERNEL_HWCAP_ASIMDDP ilog2(HWCAP_ASIMDDP) > +#define KERNEL_HWCAP_SHA512 ilog2(HWCAP_SHA512) > +#define KERNEL_HWCAP_SVE ilog2(HWCAP_SVE) > +#define KERNEL_HWCAP_ASIMDFHM ilog2(HWCAP_ASIMDFHM) > +#define KERNEL_HWCAP_DIT ilog2(HWCAP_DIT) > +#define KERNEL_HWCAP_USCAT ilog2(HWCAP_USCAT) > +#define KERNEL_HWCAP_ILRCPC ilog2(HWCAP_ILRCPC) > +#define KERNEL_HWCAP_FLAGM ilog2(HWCAP_FLAGM) > +#define KERNEL_HWCAP_SSBS ilog2(HWCAP_SSBS) > +#define KERNEL_HWCAP_SB ilog2(HWCAP_SB) > +#define KERNEL_HWCAP_PACA ilog2(HWCAP_PACA) > +#define KERNEL_HWCAP_PACG ilog2(HWCAP_PACG) Nit: Odd spacing? Personally I wouldn't indent with spaces just so that (ilog2() + 32) lines up nicely, but that's just my opinion and not a huge deal. (The spacing can make subsequent diffs look jagged by default, which can be a distraction for reviewers.) > + > #ifndef __ASSEMBLY__ > /* > * This yields a mask that user programs can use to figure out what > * instruction set this cpu supports. > */ > -#define ELF_HWCAP (elf_hwcap) > +#define ELF_HWCAP elf_hwcap > +#define ELF_HWCAP2 elf_hwcap2 Do we need elf_hwcap2 at all? We could just have these macros fish the bits out of a single variable, or wherever. However, it may be better to keep things this way if we want to maintain the elf_hwcap in the kernel/module ABI. See note on EXPORT_SYMBOL_GPL() removal for elf_hwcap in the subsequent patch. > > #ifdef CONFIG_COMPAT > #define COMPAT_ELF_HWCAP (compat_elf_hwcap) > @@ -60,6 +97,6 @@ enum { > #endif > }; > > -extern unsigned long elf_hwcap; > +extern unsigned long elf_hwcap, elf_hwcap2; > #endif > #endif > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h > index 5f0750c..453b45a 100644 > --- a/arch/arm64/include/uapi/asm/hwcap.h > +++ b/arch/arm64/include/uapi/asm/hwcap.h > @@ -18,7 +18,7 @@ > #define _UAPI__ASM_HWCAP_H > > /* > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP > + * HWCAP flags - for AT_HWCAP > */ > #define HWCAP_FP (1 << 0) > #define HWCAP_ASIMD (1 << 1) > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > index f6d84e2..d10a455 100644 > --- a/arch/arm64/kernel/cpufeature.c > +++ b/arch/arm64/kernel/cpufeature.c > @@ -38,6 +38,9 @@ > unsigned long elf_hwcap __read_mostly; > EXPORT_SYMBOL_GPL(elf_hwcap); > > +unsigned long elf_hwcap2 __read_mostly; > +EXPORT_SYMBOL_GPL(elf_hwcap2); > + Historically nobody used this because it didn't exist, and we don't want anybody to use it (since cpu_have_feature() etc. is the preferred interface). So lose EXPORT_SYMBOL_GPL() here. (You remove it in any case in a subsequent patch, but having it even transiently sends mixed messages about the intent.) [...] Otherwise looks reasonable. Cheers ---Dave
On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote: > On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote: > > As we will exhaust the first 32 bits of ELF_HWCAP let's start > > exposing ELF_HWCAP2 to userspace. > > > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we > > prefer to expand into ELF_HWCAP2 in order to provide a consistent > > view to userspace between ILP32 and LP64. > > > > To reduce complexity and allow for future expansion, we now > > represent hwcaps in the kernel as ordinals and use a > > KERNEL_HWCAP_ prefix. This allows us to support automatic feature > > based module loading for all our hwcaps. > > > > We introduce cpu_set_feature to set hwcaps in the relevant > > elf_hwcapX variable which compliments the existing cpu_have_feature > > helper. These helpers allow us to clean up existing direct uses of > > elf_hwcap. > > > > Signed-off-by: Andrew Murray <andrew.murray@arm.com> > > --- > > [...] > > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > > index dfcfba7..15d939e 100644 > > --- a/arch/arm64/include/asm/cpufeature.h > > +++ b/arch/arm64/include/asm/cpufeature.h > > @@ -18,11 +18,10 @@ > > * In the arm64 world (as in the ARM world), elf_hwcap is used both internally > > * in the kernel and for user space to keep track of which optional features > > * are supported by the current system. So let's map feature 'x' to HWCAP_x. > > - * Note that HWCAP_x constants are bit fields so we need to take the log. > > */ > > > > -#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) > > -#define cpu_feature(x) ilog2(HWCAP_ ## x) > > +#define MAX_CPU_FEATURES (2 * 8 * sizeof(unsigned long)) > > Doesn't this make 2 * 8 * 8 == 128? > > Maybe just say "64". We open-code 32 later anyway. I guess 128 would have been correct if we use all the bits of each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be 32 bits. I'll set this to 64 as you suggest. > > > +#define cpu_feature(x) (KERNEL_HWCAP_ ## x) > > > > #ifndef __ASSEMBLY__ > > > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready; > > > > bool this_cpu_has_cap(unsigned int cap); > > > > +static inline void cpu_set_feature(unsigned int num) > > +{ > > + if (num < 32) > > + elf_hwcap |= BIT(num); > > + else > > + elf_hwcap2 |= BIT(num - 32); > > +} > > + > > static inline bool cpu_have_feature(unsigned int num) > > { > > - return elf_hwcap & (1UL << num); > > + if (num < 32) > > + return elf_hwcap & BIT(num); > > + else > > + return elf_hwcap2 & BIT(num - 32); > > } > > Nit: I worry a bit that people will blithely pass HWCAP_foo to these, > not realising that the interface has changed. Yeah this would be an easy mistake to make. > > Can we do something like the following: > > static inline bool __cpu_have_feature(unsigned int num) > { > if (WARN_ON(num >= 64)) > return false; > > if (num < 32) > return elf_hwcap & BIT(num); > else > return elf_hwcap2 & BIT(num); > } > > #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name)) It took me a while to figure out what the benefit of the above line is - this means that callers of cpu_have_feature must use the unprefixed feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512 or HWCAP_SHA512) would result in a compile time error. Whereas without this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors yet resulting in incorrectly passing a bitfield when using HWCAP_x. > > > In compiletime-constant cases, the compiler should simply delete the > WARN. Is this really needed? Surely this would only come into play when a user directly calls __cpu_have_feature. I think this is overkill, especially as __cpu_have_feature is a new function. > A couple of cases in the cpufeatures and /proc/cpuinfo code would > need to use __cpu_have_feature directly and would retain the WARN, but > that's not fastpath and probably not the end of the world, plus we > get an additional debugging aid if that code goes wrong. But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit. The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c), this also uses cpu_have_feature - this expects cpu_have_feature to take an ordinal. How can we work around this? > > Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making > it impossible to specify invalid or user-encoded hwcaps there either. > Then we might justifiably omit the policing in __cpu_have_feature() > altogether. This would certainly please checkpatch with respect to line lengths :) However since this patchset, we now use cpu_have_feature elsewhere, such as in the crypto drivers. > > > > > /* System capability check for constant caps */ > > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h > > index 400b80b..05ee9b9 100644 > > --- a/arch/arm64/include/asm/hwcap.h > > +++ b/arch/arm64/include/asm/hwcap.h > > @@ -39,12 +39,49 @@ > > #define COMPAT_HWCAP2_SHA2 (1 << 3) > > #define COMPAT_HWCAP2_CRC32 (1 << 4) > > > > +/* > > + * KERNEL_HWCAP flags - for elf_hwcap (in kernel) > > + */ > > +#define KERNEL_HWCAP_FP ilog2(HWCAP_FP) > > +#define KERNEL_HWCAP_ASIMD ilog2(HWCAP_ASIMD) > > +#define KERNEL_HWCAP_EVTSTRM ilog2(HWCAP_EVTSTRM) > > +#define KERNEL_HWCAP_AES ilog2(HWCAP_AES) > > +#define KERNEL_HWCAP_PMULL ilog2(HWCAP_PMULL) > > +#define KERNEL_HWCAP_SHA1 ilog2(HWCAP_SHA1) > > +#define KERNEL_HWCAP_SHA2 ilog2(HWCAP_SHA2) > > +#define KERNEL_HWCAP_CRC32 ilog2(HWCAP_CRC32) > > +#define KERNEL_HWCAP_ATOMICS ilog2(HWCAP_ATOMICS) > > +#define KERNEL_HWCAP_FPHP ilog2(HWCAP_FPHP) > > +#define KERNEL_HWCAP_ASIMDHP ilog2(HWCAP_ASIMDHP) > > +#define KERNEL_HWCAP_CPUID ilog2(HWCAP_CPUID) > > +#define KERNEL_HWCAP_ASIMDRDM ilog2(HWCAP_ASIMDRDM) > > +#define KERNEL_HWCAP_JSCVT ilog2(HWCAP_JSCVT) > > +#define KERNEL_HWCAP_FCMA ilog2(HWCAP_FCMA) > > +#define KERNEL_HWCAP_LRCPC ilog2(HWCAP_LRCPC) > > +#define KERNEL_HWCAP_DCPOP ilog2(HWCAP_DCPOP) > > +#define KERNEL_HWCAP_SHA3 ilog2(HWCAP_SHA3) > > +#define KERNEL_HWCAP_SM3 ilog2(HWCAP_SM3) > > +#define KERNEL_HWCAP_SM4 ilog2(HWCAP_SM4) > > +#define KERNEL_HWCAP_ASIMDDP ilog2(HWCAP_ASIMDDP) > > +#define KERNEL_HWCAP_SHA512 ilog2(HWCAP_SHA512) > > +#define KERNEL_HWCAP_SVE ilog2(HWCAP_SVE) > > +#define KERNEL_HWCAP_ASIMDFHM ilog2(HWCAP_ASIMDFHM) > > +#define KERNEL_HWCAP_DIT ilog2(HWCAP_DIT) > > +#define KERNEL_HWCAP_USCAT ilog2(HWCAP_USCAT) > > +#define KERNEL_HWCAP_ILRCPC ilog2(HWCAP_ILRCPC) > > +#define KERNEL_HWCAP_FLAGM ilog2(HWCAP_FLAGM) > > +#define KERNEL_HWCAP_SSBS ilog2(HWCAP_SSBS) > > +#define KERNEL_HWCAP_SB ilog2(HWCAP_SB) > > +#define KERNEL_HWCAP_PACA ilog2(HWCAP_PACA) > > +#define KERNEL_HWCAP_PACG ilog2(HWCAP_PACG) > > Nit: Odd spacing? Personally I wouldn't indent with spaces just so that > (ilog2() + 32) lines up nicely, but that's just my opinion and not a > huge deal. > > (The spacing can make subsequent diffs look jagged by default, which > can be a distraction for reviewers.) I'll convert to tabs, I probably copy pasted and the tabs got converted. > > > + > > #ifndef __ASSEMBLY__ > > /* > > * This yields a mask that user programs can use to figure out what > > * instruction set this cpu supports. > > */ > > -#define ELF_HWCAP (elf_hwcap) > > +#define ELF_HWCAP elf_hwcap > > +#define ELF_HWCAP2 elf_hwcap2 > > Do we need elf_hwcap2 at all? > > We could just have these macros fish the bits out of a single variable, > or wherever. > > However, it may be better to keep things this way if we want to maintain > the elf_hwcap in the kernel/module ABI. See note on EXPORT_SYMBOL_GPL() > removal for elf_hwcap in the subsequent patch. OK, I'll leave it as it is. > > > > > #ifdef CONFIG_COMPAT > > #define COMPAT_ELF_HWCAP (compat_elf_hwcap) > > @@ -60,6 +97,6 @@ enum { > > #endif > > }; > > > > -extern unsigned long elf_hwcap; > > +extern unsigned long elf_hwcap, elf_hwcap2; > > #endif > > #endif > > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h > > index 5f0750c..453b45a 100644 > > --- a/arch/arm64/include/uapi/asm/hwcap.h > > +++ b/arch/arm64/include/uapi/asm/hwcap.h > > @@ -18,7 +18,7 @@ > > #define _UAPI__ASM_HWCAP_H > > > > /* > > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP > > + * HWCAP flags - for AT_HWCAP > > */ > > #define HWCAP_FP (1 << 0) > > #define HWCAP_ASIMD (1 << 1) > > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > > index f6d84e2..d10a455 100644 > > --- a/arch/arm64/kernel/cpufeature.c > > +++ b/arch/arm64/kernel/cpufeature.c > > @@ -38,6 +38,9 @@ > > unsigned long elf_hwcap __read_mostly; > > EXPORT_SYMBOL_GPL(elf_hwcap); > > > > +unsigned long elf_hwcap2 __read_mostly; > > +EXPORT_SYMBOL_GPL(elf_hwcap2); > > + > > Historically nobody used this because it didn't exist, and we don't want > anybody to use it (since cpu_have_feature() etc. is the preferred > interface). In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature. > > So lose EXPORT_SYMBOL_GPL() here. (You remove it in any case in a > subsequent patch, but having it even transiently sends mixed messages > about the intent.) No problem. > > [...] > > Otherwise looks reasonable. Thanks for the review. Andrew Murray > > Cheers > ---Dave
On Mon, Feb 18, 2019 at 03:32:06PM +0000, Andrew Murray wrote: > On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote: > > On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote: > > > As we will exhaust the first 32 bits of ELF_HWCAP let's start > > > exposing ELF_HWCAP2 to userspace. > > > > > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we > > > prefer to expand into ELF_HWCAP2 in order to provide a consistent > > > view to userspace between ILP32 and LP64. > > > > > > To reduce complexity and allow for future expansion, we now > > > represent hwcaps in the kernel as ordinals and use a > > > KERNEL_HWCAP_ prefix. This allows us to support automatic feature > > > based module loading for all our hwcaps. > > > > > > We introduce cpu_set_feature to set hwcaps in the relevant > > > elf_hwcapX variable which compliments the existing cpu_have_feature > > > helper. These helpers allow us to clean up existing direct uses of > > > elf_hwcap. > > > > > > Signed-off-by: Andrew Murray <andrew.murray@arm.com> > > > --- > > > > [...] > > > > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > > > index dfcfba7..15d939e 100644 > > > --- a/arch/arm64/include/asm/cpufeature.h > > > +++ b/arch/arm64/include/asm/cpufeature.h > > > @@ -18,11 +18,10 @@ > > > * In the arm64 world (as in the ARM world), elf_hwcap is used both internally > > > * in the kernel and for user space to keep track of which optional features > > > * are supported by the current system. So let's map feature 'x' to HWCAP_x. > > > - * Note that HWCAP_x constants are bit fields so we need to take the log. > > > */ > > > > > > -#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) > > > -#define cpu_feature(x) ilog2(HWCAP_ ## x) > > > +#define MAX_CPU_FEATURES (2 * 8 * sizeof(unsigned long)) > > > > Doesn't this make 2 * 8 * 8 == 128? > > > > Maybe just say "64". We open-code 32 later anyway. > > I guess 128 would have been correct if we use all the bits of > each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be > 32 bits. > > I'll set this to 64 as you suggest. > > > > > > +#define cpu_feature(x) (KERNEL_HWCAP_ ## x) > > > > > > #ifndef __ASSEMBLY__ > > > > > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready; > > > > > > bool this_cpu_has_cap(unsigned int cap); > > > > > > +static inline void cpu_set_feature(unsigned int num) > > > +{ > > > + if (num < 32) > > > + elf_hwcap |= BIT(num); > > > + else > > > + elf_hwcap2 |= BIT(num - 32); > > > +} > > > + > > > static inline bool cpu_have_feature(unsigned int num) > > > { > > > - return elf_hwcap & (1UL << num); > > > + if (num < 32) > > > + return elf_hwcap & BIT(num); > > > + else > > > + return elf_hwcap2 & BIT(num - 32); > > > } > > > > Nit: I worry a bit that people will blithely pass HWCAP_foo to these, > > not realising that the interface has changed. > > Yeah this would be an easy mistake to make. > > > > > Can we do something like the following: > > > > static inline bool __cpu_have_feature(unsigned int num) > > { > > if (WARN_ON(num >= 64)) > > return false; > > > > if (num < 32) > > return elf_hwcap & BIT(num); > > else > > return elf_hwcap2 & BIT(num); > > } > > > > #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name)) > > It took me a while to figure out what the benefit of the above line > is - this means that callers of cpu_have_feature must use the unprefixed > feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512 > or HWCAP_SHA512) would result in a compile time error. Whereas without > this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors > yet resulting in incorrectly passing a bitfield when using HWCAP_x. That was the idea (apologies for being cryptic...) > > In compiletime-constant cases, the compiler should simply delete the > > WARN. > > Is this really needed? Surely this would only come into play when a user > directly calls __cpu_have_feature. I think this is overkill, especially > as __cpu_have_feature is a new function. > > > A couple of cases in the cpufeatures and /proc/cpuinfo code would > > need to use __cpu_have_feature directly and would retain the WARN, but > > that's not fastpath and probably not the end of the world, plus we > > get an additional debugging aid if that code goes wrong. > > But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit. Sure, since we don't expect general purpose callers to use __cpu_have_feature() directly it is a bit paranoid to include the WARN. Given the contexts in which this is used, I wouldn't lose sleep if it weren't there. > The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c), > this also uses cpu_have_feature - this expects cpu_have_feature to take > an ordinal. How can we work around this? > > > > > Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making > > it impossible to specify invalid or user-encoded hwcaps there either. > > Then we might justifiably omit the policing in __cpu_have_feature() > > altogether. > > This would certainly please checkpatch with respect to line lengths :) > > However since this patchset, we now use cpu_have_feature elsewhere, such > as in the crypto drivers. Hmmm, those are irksome issues. It would be nice to split the ordinal versus symbolic cpu_have_feature() into separate macros, but that would involve a change to code outside arch/arm64. It's almost certainly not worth the pain. Can you take a look at arch/arm? That already has hwcap2. It may makes some sense to follow a common approach, although I'm not sure how #define __hwcap_feature(x) ilog2(HWCAP_ ## x) #define __hwcap2_feature(x) (32 + ilog2(HWCAP2_ ## x)) #define cpu_feature(x) __hwcap2_feature(x) is supposed to work for cpu_feature(SWP) for example... Maybe I missed something. > > > /* System capability check for constant caps */ > > > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h > > > index 400b80b..05ee9b9 100644 > > > --- a/arch/arm64/include/asm/hwcap.h > > > +++ b/arch/arm64/include/asm/hwcap.h > > > @@ -39,12 +39,49 @@ [...] > > > +#define KERNEL_HWCAP_SSBS ilog2(HWCAP_SSBS) > > > +#define KERNEL_HWCAP_SB ilog2(HWCAP_SB) > > > +#define KERNEL_HWCAP_PACA ilog2(HWCAP_PACA) > > > +#define KERNEL_HWCAP_PACG ilog2(HWCAP_PACG) > > > > Nit: Odd spacing? Personally I wouldn't indent with spaces just so that > > (ilog2() + 32) lines up nicely, but that's just my opinion and not a > > huge deal. > > > > (The spacing can make subsequent diffs look jagged by default, which > > can be a distraction for reviewers.) > > I'll convert to tabs, I probably copy pasted and the tabs got converted. > > > > > > + > > > #ifndef __ASSEMBLY__ > > > /* > > > * This yields a mask that user programs can use to figure out what > > > * instruction set this cpu supports. > > > */ > > > -#define ELF_HWCAP (elf_hwcap) > > > +#define ELF_HWCAP elf_hwcap > > > +#define ELF_HWCAP2 elf_hwcap2 > > > > Do we need elf_hwcap2 at all? > > > > We could just have these macros fish the bits out of a single variable, > > or wherever. > > > > However, it may be better to keep things this way if we want to maintain > > the elf_hwcap in the kernel/module ABI. See note on EXPORT_SYMBOL_GPL() > > removal for elf_hwcap in the subsequent patch. > > OK, I'll leave it as it is. > > > > > > > > > #ifdef CONFIG_COMPAT > > > #define COMPAT_ELF_HWCAP (compat_elf_hwcap) > > > @@ -60,6 +97,6 @@ enum { > > > #endif > > > }; > > > > > > -extern unsigned long elf_hwcap; > > > +extern unsigned long elf_hwcap, elf_hwcap2; > > > #endif > > > #endif > > > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h > > > index 5f0750c..453b45a 100644 > > > --- a/arch/arm64/include/uapi/asm/hwcap.h > > > +++ b/arch/arm64/include/uapi/asm/hwcap.h > > > @@ -18,7 +18,7 @@ > > > #define _UAPI__ASM_HWCAP_H > > > > > > /* > > > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP > > > + * HWCAP flags - for AT_HWCAP > > > */ > > > #define HWCAP_FP (1 << 0) > > > #define HWCAP_ASIMD (1 << 1) > > > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > > > index f6d84e2..d10a455 100644 > > > --- a/arch/arm64/kernel/cpufeature.c > > > +++ b/arch/arm64/kernel/cpufeature.c > > > @@ -38,6 +38,9 @@ > > > unsigned long elf_hwcap __read_mostly; > > > EXPORT_SYMBOL_GPL(elf_hwcap); > > > > > > +unsigned long elf_hwcap2 __read_mostly; > > > +EXPORT_SYMBOL_GPL(elf_hwcap2); > > > + > > > > Historically nobody used this because it didn't exist, and we don't want > > anybody to use it (since cpu_have_feature() etc. is the preferred > > interface). > > In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature. > > > > > So lose EXPORT_SYMBOL_GPL() here. (You remove it in any case in a > > subsequent patch, but having it even transiently sends mixed messages > > about the intent.) > > No problem. Hmmm, since this inline in a header we'd have to EXPORT_SYMBOL_GPL the things it depends on (elf_hwcap, elf_hwcap2) rather than the (inline) function itself. So maybe we can't do better than the current situation after all. If so, I guess exporting elf_hwcap2 as GPL is OK. Cheers ---Dave
On Mon, Feb 18, 2019 at 04:02:38PM +0000, Dave Martin wrote: > On Mon, Feb 18, 2019 at 03:32:06PM +0000, Andrew Murray wrote: > > On Thu, Feb 07, 2019 at 11:31:24AM +0000, Dave Martin wrote: > > > On Wed, Feb 06, 2019 at 01:31:04PM +0000, Andrew Murray wrote: > > > > As we will exhaust the first 32 bits of ELF_HWCAP let's start > > > > exposing ELF_HWCAP2 to userspace. > > > > > > > > Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we > > > > prefer to expand into ELF_HWCAP2 in order to provide a consistent > > > > view to userspace between ILP32 and LP64. > > > > > > > > To reduce complexity and allow for future expansion, we now > > > > represent hwcaps in the kernel as ordinals and use a > > > > KERNEL_HWCAP_ prefix. This allows us to support automatic feature > > > > based module loading for all our hwcaps. > > > > > > > > We introduce cpu_set_feature to set hwcaps in the relevant > > > > elf_hwcapX variable which compliments the existing cpu_have_feature > > > > helper. These helpers allow us to clean up existing direct uses of > > > > elf_hwcap. > > > > > > > > Signed-off-by: Andrew Murray <andrew.murray@arm.com> > > > > --- > > > > > > [...] > > > > > > > diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h > > > > index dfcfba7..15d939e 100644 > > > > --- a/arch/arm64/include/asm/cpufeature.h > > > > +++ b/arch/arm64/include/asm/cpufeature.h > > > > @@ -18,11 +18,10 @@ > > > > * In the arm64 world (as in the ARM world), elf_hwcap is used both internally > > > > * in the kernel and for user space to keep track of which optional features > > > > * are supported by the current system. So let's map feature 'x' to HWCAP_x. > > > > - * Note that HWCAP_x constants are bit fields so we need to take the log. > > > > */ > > > > > > > > -#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) > > > > -#define cpu_feature(x) ilog2(HWCAP_ ## x) > > > > +#define MAX_CPU_FEATURES (2 * 8 * sizeof(unsigned long)) > > > > > > Doesn't this make 2 * 8 * 8 == 128? > > > > > > Maybe just say "64". We open-code 32 later anyway. > > > > I guess 128 would have been correct if we use all the bits of > > each ELF_HWCAP{,2} - but we chose to limit each ELF_HWCAP to be > > 32 bits. > > > > I'll set this to 64 as you suggest. > > > > > > > > > +#define cpu_feature(x) (KERNEL_HWCAP_ ## x) > > > > > > > > #ifndef __ASSEMBLY__ > > > > > > > > @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready; > > > > > > > > bool this_cpu_has_cap(unsigned int cap); > > > > > > > > +static inline void cpu_set_feature(unsigned int num) > > > > +{ > > > > + if (num < 32) > > > > + elf_hwcap |= BIT(num); > > > > + else > > > > + elf_hwcap2 |= BIT(num - 32); > > > > +} > > > > + > > > > static inline bool cpu_have_feature(unsigned int num) > > > > { > > > > - return elf_hwcap & (1UL << num); > > > > + if (num < 32) > > > > + return elf_hwcap & BIT(num); > > > > + else > > > > + return elf_hwcap2 & BIT(num - 32); > > > > } > > > > > > Nit: I worry a bit that people will blithely pass HWCAP_foo to these, > > > not realising that the interface has changed. > > > > Yeah this would be an easy mistake to make. > > > > > > > > Can we do something like the following: > > > > > > static inline bool __cpu_have_feature(unsigned int num) > > > { > > > if (WARN_ON(num >= 64)) > > > return false; > > > > > > if (num < 32) > > > return elf_hwcap & BIT(num); > > > else > > > return elf_hwcap2 & BIT(num); > > > } > > > > > > #define cpu_have_feature(name) __cpu_have_feature(cpu_feature(name)) > > > > It took me a while to figure out what the benefit of the above line > > is - this means that callers of cpu_have_feature must use the unprefixed > > feature name (e.g. SHA512), anything else such as (KERNEL_HWCAP_SHA512 > > or HWCAP_SHA512) would result in a compile time error. Whereas without > > this users could pass KERNEL_HWCAP_x or HWCAP_x without compile errors > > yet resulting in incorrectly passing a bitfield when using HWCAP_x. > > That was the idea (apologies for being cryptic...) :) > > > > In compiletime-constant cases, the compiler should simply delete the > > > WARN. > > > > Is this really needed? Surely this would only come into play when a user > > directly calls __cpu_have_feature. I think this is overkill, especially > > as __cpu_have_feature is a new function. > > > > > A couple of cases in the cpufeatures and /proc/cpuinfo code would > > > need to use __cpu_have_feature directly and would retain the WARN, but > > > that's not fastpath and probably not the end of the world, plus we > > > get an additional debugging aid if that code goes wrong. > > > > But even so, the WARN (for the cpuinfo case) is unlikely to ever be hit. > > Sure, since we don't expect general purpose callers to use > __cpu_have_feature() directly it is a bit paranoid to include the WARN. > Given the contexts in which this is used, I wouldn't lose sleep if it > weren't there. > > > The challenge with this approach is print_cpu_modalias (drivers/base/cpu.c), > > this also uses cpu_have_feature - this expects cpu_have_feature to take > > an ordinal. How can we work around this? > > > > > > > > Alternatively, we could bake cpu_feature() into HWCAP_CAP(), making > > > it impossible to specify invalid or user-encoded hwcaps there either. > > > Then we might justifiably omit the policing in __cpu_have_feature() > > > altogether. > > > > This would certainly please checkpatch with respect to line lengths :) > > > > However since this patchset, we now use cpu_have_feature elsewhere, such > > as in the crypto drivers. > > Hmmm, those are irksome issues. > > It would be nice to split the ordinal versus symbolic cpu_have_feature() > into separate macros, but that would involve a change to code outside > arch/arm64. It's almost certainly not worth the pain. > > > Can you take a look at arch/arm? That already has hwcap2. > It may makes some sense to follow a common approach, although I'm not > sure how > > #define __hwcap_feature(x) ilog2(HWCAP_ ## x) > #define __hwcap2_feature(x) (32 + ilog2(HWCAP2_ ## x)) > #define cpu_feature(x) __hwcap2_feature(x) > > is supposed to work for cpu_feature(SWP) for example... Maybe I missed > something. The limitation with the arm32 approach is that you can only support automatic module loading with features covered in HWCAP2. We can avoid this. For arm32 cpu_feature(AES) will only match within HWCAP2, you would get unintended behaviour if you used a feature name from HWCAP such as NEON. Thus cpu_have_feature(cpu_feature(X)) is limited to HWCAP2. Prior to this patchset cpu_have_feature had a sole user and that is print_cpu_modalias. CPU features are normally tested by directly comparing against elf_hwcap. > > > > > /* System capability check for constant caps */ > > > > diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h > > > > index 400b80b..05ee9b9 100644 > > > > --- a/arch/arm64/include/asm/hwcap.h > > > > +++ b/arch/arm64/include/asm/hwcap.h > > > > @@ -39,12 +39,49 @@ > > [...] > > > > > +#define KERNEL_HWCAP_SSBS ilog2(HWCAP_SSBS) > > > > +#define KERNEL_HWCAP_SB ilog2(HWCAP_SB) > > > > +#define KERNEL_HWCAP_PACA ilog2(HWCAP_PACA) > > > > +#define KERNEL_HWCAP_PACG ilog2(HWCAP_PACG) > > > > > > Nit: Odd spacing? Personally I wouldn't indent with spaces just so that > > > (ilog2() + 32) lines up nicely, but that's just my opinion and not a > > > huge deal. > > > > > > (The spacing can make subsequent diffs look jagged by default, which > > > can be a distraction for reviewers.) > > > > I'll convert to tabs, I probably copy pasted and the tabs got converted. > > > > > > > > > + > > > > #ifndef __ASSEMBLY__ > > > > /* > > > > * This yields a mask that user programs can use to figure out what > > > > * instruction set this cpu supports. > > > > */ > > > > -#define ELF_HWCAP (elf_hwcap) > > > > +#define ELF_HWCAP elf_hwcap > > > > +#define ELF_HWCAP2 elf_hwcap2 > > > > > > Do we need elf_hwcap2 at all? > > > > > > We could just have these macros fish the bits out of a single variable, > > > or wherever. > > > > > > However, it may be better to keep things this way if we want to maintain > > > the elf_hwcap in the kernel/module ABI. See note on EXPORT_SYMBOL_GPL() > > > removal for elf_hwcap in the subsequent patch. > > > > OK, I'll leave it as it is. > > > > > > > > > > > > > #ifdef CONFIG_COMPAT > > > > #define COMPAT_ELF_HWCAP (compat_elf_hwcap) > > > > @@ -60,6 +97,6 @@ enum { > > > > #endif > > > > }; > > > > > > > > -extern unsigned long elf_hwcap; > > > > +extern unsigned long elf_hwcap, elf_hwcap2; > > > > #endif > > > > #endif > > > > diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h > > > > index 5f0750c..453b45a 100644 > > > > --- a/arch/arm64/include/uapi/asm/hwcap.h > > > > +++ b/arch/arm64/include/uapi/asm/hwcap.h > > > > @@ -18,7 +18,7 @@ > > > > #define _UAPI__ASM_HWCAP_H > > > > > > > > /* > > > > - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP > > > > + * HWCAP flags - for AT_HWCAP > > > > */ > > > > #define HWCAP_FP (1 << 0) > > > > #define HWCAP_ASIMD (1 << 1) > > > > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c > > > > index f6d84e2..d10a455 100644 > > > > --- a/arch/arm64/kernel/cpufeature.c > > > > +++ b/arch/arm64/kernel/cpufeature.c > > > > @@ -38,6 +38,9 @@ > > > > unsigned long elf_hwcap __read_mostly; > > > > EXPORT_SYMBOL_GPL(elf_hwcap); > > > > > > > > +unsigned long elf_hwcap2 __read_mostly; > > > > +EXPORT_SYMBOL_GPL(elf_hwcap2); > > > > + > > > > > > Historically nobody used this because it didn't exist, and we don't want > > > anybody to use it (since cpu_have_feature() etc. is the preferred > > > interface). > > > > In that case I should probably EXPORT_SYMBOL_GPL cpu_have_feature. > > > > > > > > So lose EXPORT_SYMBOL_GPL() here. (You remove it in any case in a > > > subsequent patch, but having it even transiently sends mixed messages > > > about the intent.) > > > > No problem. > > Hmmm, since this inline in a header we'd have to EXPORT_SYMBOL_GPL the > things it depends on (elf_hwcap, elf_hwcap2) rather than the (inline) > function itself. > > So maybe we can't do better than the current situation after all. > > If so, I guess exporting elf_hwcap2 as GPL is OK. Actually my patchset moves the cpu_have_feature function a C file. So I could add a EXPORT_SYMBOL_GPL to this and the other functions I introduce (cpu_set_feature, cpu_get_elf_hwcap{,2}). Unless you have objections I'll respin with this approach. Andrew Murray > > Cheers > ---Dave
diff --git a/arch/arm64/crypto/aes-ce-ccm-glue.c b/arch/arm64/crypto/aes-ce-ccm-glue.c index 68b11aa..8bca470 100644 --- a/arch/arm64/crypto/aes-ce-ccm-glue.c +++ b/arch/arm64/crypto/aes-ce-ccm-glue.c @@ -374,7 +374,7 @@ static struct aead_alg ccm_aes_alg = { static int __init aes_mod_init(void) { - if (!(elf_hwcap & HWCAP_AES)) + if (!cpu_have_feature(KERNEL_HWCAP_AES)) return -ENODEV; return crypto_register_aead(&ccm_aes_alg); } diff --git a/arch/arm64/crypto/aes-neonbs-glue.c b/arch/arm64/crypto/aes-neonbs-glue.c index e7a95a5..e5a8334 100644 --- a/arch/arm64/crypto/aes-neonbs-glue.c +++ b/arch/arm64/crypto/aes-neonbs-glue.c @@ -440,7 +440,7 @@ static int __init aes_init(void) int err; int i; - if (!(elf_hwcap & HWCAP_ASIMD)) + if (!cpu_have_feature(KERNEL_HWCAP_ASIMD)) return -ENODEV; err = crypto_register_skciphers(aes_algs, ARRAY_SIZE(aes_algs)); diff --git a/arch/arm64/crypto/chacha-neon-glue.c b/arch/arm64/crypto/chacha-neon-glue.c index bece1d8..54de986 100644 --- a/arch/arm64/crypto/chacha-neon-glue.c +++ b/arch/arm64/crypto/chacha-neon-glue.c @@ -173,7 +173,7 @@ static struct skcipher_alg algs[] = { static int __init chacha_simd_mod_init(void) { - if (!(elf_hwcap & HWCAP_ASIMD)) + if (!cpu_have_feature(KERNEL_HWCAP_ASIMD)) return -ENODEV; return crypto_register_skciphers(algs, ARRAY_SIZE(algs)); diff --git a/arch/arm64/crypto/crct10dif-ce-glue.c b/arch/arm64/crypto/crct10dif-ce-glue.c index b461d62..d78d123 100644 --- a/arch/arm64/crypto/crct10dif-ce-glue.c +++ b/arch/arm64/crypto/crct10dif-ce-glue.c @@ -88,7 +88,7 @@ static struct shash_alg crc_t10dif_alg = { static int __init crc_t10dif_mod_init(void) { - if (elf_hwcap & HWCAP_PMULL) + if (cpu_have_feature(KERNEL_HWCAP_PMULL)) crc_t10dif_pmull = crc_t10dif_pmull_p64; else crc_t10dif_pmull = crc_t10dif_pmull_p8; diff --git a/arch/arm64/crypto/ghash-ce-glue.c b/arch/arm64/crypto/ghash-ce-glue.c index 067d893..f3aa5dd 100644 --- a/arch/arm64/crypto/ghash-ce-glue.c +++ b/arch/arm64/crypto/ghash-ce-glue.c @@ -646,10 +646,10 @@ static int __init ghash_ce_mod_init(void) { int ret; - if (!(elf_hwcap & HWCAP_ASIMD)) + if (!cpu_have_feature(KERNEL_HWCAP_ASIMD)) return -ENODEV; - if (elf_hwcap & HWCAP_PMULL) + if (cpu_have_feature(KERNEL_HWCAP_PMULL)) pmull_ghash_update = pmull_ghash_update_p64; else @@ -659,7 +659,7 @@ static int __init ghash_ce_mod_init(void) if (ret) return ret; - if (elf_hwcap & HWCAP_PMULL) { + if (cpu_have_feature(KERNEL_HWCAP_PMULL)) { ret = crypto_register_aead(&gcm_aes_alg); if (ret) crypto_unregister_shash(&ghash_alg); diff --git a/arch/arm64/crypto/nhpoly1305-neon-glue.c b/arch/arm64/crypto/nhpoly1305-neon-glue.c index 22cc32a..7e6815b 100644 --- a/arch/arm64/crypto/nhpoly1305-neon-glue.c +++ b/arch/arm64/crypto/nhpoly1305-neon-glue.c @@ -56,7 +56,7 @@ static struct shash_alg nhpoly1305_alg = { static int __init nhpoly1305_mod_init(void) { - if (!(elf_hwcap & HWCAP_ASIMD)) + if (!cpu_have_feature(KERNEL_HWCAP_ASIMD)) return -ENODEV; return crypto_register_shash(&nhpoly1305_alg); diff --git a/arch/arm64/crypto/sha256-glue.c b/arch/arm64/crypto/sha256-glue.c index 4aedeae..7799f4c 100644 --- a/arch/arm64/crypto/sha256-glue.c +++ b/arch/arm64/crypto/sha256-glue.c @@ -173,7 +173,7 @@ static int __init sha256_mod_init(void) if (ret) return ret; - if (elf_hwcap & HWCAP_ASIMD) { + if (cpu_have_feature(KERNEL_HWCAP_ASIMD)) { ret = crypto_register_shashes(neon_algs, ARRAY_SIZE(neon_algs)); if (ret) crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); @@ -183,7 +183,7 @@ static int __init sha256_mod_init(void) static void __exit sha256_mod_fini(void) { - if (elf_hwcap & HWCAP_ASIMD) + if (cpu_have_feature(KERNEL_HWCAP_ASIMD)) crypto_unregister_shashes(neon_algs, ARRAY_SIZE(neon_algs)); crypto_unregister_shashes(algs, ARRAY_SIZE(algs)); } diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h index dfcfba7..15d939e 100644 --- a/arch/arm64/include/asm/cpufeature.h +++ b/arch/arm64/include/asm/cpufeature.h @@ -18,11 +18,10 @@ * In the arm64 world (as in the ARM world), elf_hwcap is used both internally * in the kernel and for user space to keep track of which optional features * are supported by the current system. So let's map feature 'x' to HWCAP_x. - * Note that HWCAP_x constants are bit fields so we need to take the log. */ -#define MAX_CPU_FEATURES (8 * sizeof(elf_hwcap)) -#define cpu_feature(x) ilog2(HWCAP_ ## x) +#define MAX_CPU_FEATURES (2 * 8 * sizeof(unsigned long)) +#define cpu_feature(x) (KERNEL_HWCAP_ ## x) #ifndef __ASSEMBLY__ @@ -396,9 +395,20 @@ extern struct static_key_false arm64_const_caps_ready; bool this_cpu_has_cap(unsigned int cap); +static inline void cpu_set_feature(unsigned int num) +{ + if (num < 32) + elf_hwcap |= BIT(num); + else + elf_hwcap2 |= BIT(num - 32); +} + static inline bool cpu_have_feature(unsigned int num) { - return elf_hwcap & (1UL << num); + if (num < 32) + return elf_hwcap & BIT(num); + else + return elf_hwcap2 & BIT(num - 32); } /* System capability check for constant caps */ diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h index 400b80b..05ee9b9 100644 --- a/arch/arm64/include/asm/hwcap.h +++ b/arch/arm64/include/asm/hwcap.h @@ -39,12 +39,49 @@ #define COMPAT_HWCAP2_SHA2 (1 << 3) #define COMPAT_HWCAP2_CRC32 (1 << 4) +/* + * KERNEL_HWCAP flags - for elf_hwcap (in kernel) + */ +#define KERNEL_HWCAP_FP ilog2(HWCAP_FP) +#define KERNEL_HWCAP_ASIMD ilog2(HWCAP_ASIMD) +#define KERNEL_HWCAP_EVTSTRM ilog2(HWCAP_EVTSTRM) +#define KERNEL_HWCAP_AES ilog2(HWCAP_AES) +#define KERNEL_HWCAP_PMULL ilog2(HWCAP_PMULL) +#define KERNEL_HWCAP_SHA1 ilog2(HWCAP_SHA1) +#define KERNEL_HWCAP_SHA2 ilog2(HWCAP_SHA2) +#define KERNEL_HWCAP_CRC32 ilog2(HWCAP_CRC32) +#define KERNEL_HWCAP_ATOMICS ilog2(HWCAP_ATOMICS) +#define KERNEL_HWCAP_FPHP ilog2(HWCAP_FPHP) +#define KERNEL_HWCAP_ASIMDHP ilog2(HWCAP_ASIMDHP) +#define KERNEL_HWCAP_CPUID ilog2(HWCAP_CPUID) +#define KERNEL_HWCAP_ASIMDRDM ilog2(HWCAP_ASIMDRDM) +#define KERNEL_HWCAP_JSCVT ilog2(HWCAP_JSCVT) +#define KERNEL_HWCAP_FCMA ilog2(HWCAP_FCMA) +#define KERNEL_HWCAP_LRCPC ilog2(HWCAP_LRCPC) +#define KERNEL_HWCAP_DCPOP ilog2(HWCAP_DCPOP) +#define KERNEL_HWCAP_SHA3 ilog2(HWCAP_SHA3) +#define KERNEL_HWCAP_SM3 ilog2(HWCAP_SM3) +#define KERNEL_HWCAP_SM4 ilog2(HWCAP_SM4) +#define KERNEL_HWCAP_ASIMDDP ilog2(HWCAP_ASIMDDP) +#define KERNEL_HWCAP_SHA512 ilog2(HWCAP_SHA512) +#define KERNEL_HWCAP_SVE ilog2(HWCAP_SVE) +#define KERNEL_HWCAP_ASIMDFHM ilog2(HWCAP_ASIMDFHM) +#define KERNEL_HWCAP_DIT ilog2(HWCAP_DIT) +#define KERNEL_HWCAP_USCAT ilog2(HWCAP_USCAT) +#define KERNEL_HWCAP_ILRCPC ilog2(HWCAP_ILRCPC) +#define KERNEL_HWCAP_FLAGM ilog2(HWCAP_FLAGM) +#define KERNEL_HWCAP_SSBS ilog2(HWCAP_SSBS) +#define KERNEL_HWCAP_SB ilog2(HWCAP_SB) +#define KERNEL_HWCAP_PACA ilog2(HWCAP_PACA) +#define KERNEL_HWCAP_PACG ilog2(HWCAP_PACG) + #ifndef __ASSEMBLY__ /* * This yields a mask that user programs can use to figure out what * instruction set this cpu supports. */ -#define ELF_HWCAP (elf_hwcap) +#define ELF_HWCAP elf_hwcap +#define ELF_HWCAP2 elf_hwcap2 #ifdef CONFIG_COMPAT #define COMPAT_ELF_HWCAP (compat_elf_hwcap) @@ -60,6 +97,6 @@ enum { #endif }; -extern unsigned long elf_hwcap; +extern unsigned long elf_hwcap, elf_hwcap2; #endif #endif diff --git a/arch/arm64/include/uapi/asm/hwcap.h b/arch/arm64/include/uapi/asm/hwcap.h index 5f0750c..453b45a 100644 --- a/arch/arm64/include/uapi/asm/hwcap.h +++ b/arch/arm64/include/uapi/asm/hwcap.h @@ -18,7 +18,7 @@ #define _UAPI__ASM_HWCAP_H /* - * HWCAP flags - for elf_hwcap (in kernel) and AT_HWCAP + * HWCAP flags - for AT_HWCAP */ #define HWCAP_FP (1 << 0) #define HWCAP_ASIMD (1 << 1) diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c index f6d84e2..d10a455 100644 --- a/arch/arm64/kernel/cpufeature.c +++ b/arch/arm64/kernel/cpufeature.c @@ -38,6 +38,9 @@ unsigned long elf_hwcap __read_mostly; EXPORT_SYMBOL_GPL(elf_hwcap); +unsigned long elf_hwcap2 __read_mostly; +EXPORT_SYMBOL_GPL(elf_hwcap2); + #ifdef CONFIG_COMPAT #define COMPAT_ELF_HWCAP_DEFAULT \ (COMPAT_HWCAP_HALF|COMPAT_HWCAP_THUMB|\ @@ -1536,39 +1539,39 @@ static const struct arm64_cpu_capabilities ptr_auth_hwcap_gen_matches[] = { #endif static const struct arm64_cpu_capabilities arm64_elf_hwcaps[] = { - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_PMULL), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_AES), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA1), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA2), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_SHA512), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_CRC32), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ATOMICS), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDRDM), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SHA3), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SM3), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SM4), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDDP), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_ASIMDFHM), - HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_TS_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FLAGM), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_FP), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_FPHP), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, HWCAP_ASIMD), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_ASIMDHP), - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, HWCAP_DIT), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_DCPOP), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_JSCVT), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_FCMA), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_LRCPC), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, HWCAP_ILRCPC), - HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_SB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_SB), - HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, HWCAP_USCAT), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_PMULL), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_AES_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_AES), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA1_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA1), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA2), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA2_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_SHA512), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_CRC32_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_CRC32), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_ATOMICS_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ATOMICS), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_RDM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDRDM), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SHA3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SHA3), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM3_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SM3), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_SM4_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SM4), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_DP_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDDP), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_FHM_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDFHM), + HWCAP_CAP(SYS_ID_AA64ISAR0_EL1, ID_AA64ISAR0_TS_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FLAGM), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_FP), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_FP_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FPHP), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 0, CAP_HWCAP, KERNEL_HWCAP_ASIMD), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_ASIMD_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_ASIMDHP), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_DIT_SHIFT, FTR_SIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DIT), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_DPB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_DCPOP), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_JSCVT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_JSCVT), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_FCMA_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_FCMA), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_LRCPC), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_LRCPC_SHIFT, FTR_UNSIGNED, 2, CAP_HWCAP, KERNEL_HWCAP_ILRCPC), + HWCAP_CAP(SYS_ID_AA64ISAR1_EL1, ID_AA64ISAR1_SB_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_SB), + HWCAP_CAP(SYS_ID_AA64MMFR2_EL1, ID_AA64MMFR2_AT_SHIFT, FTR_UNSIGNED, 1, CAP_HWCAP, KERNEL_HWCAP_USCAT), #ifdef CONFIG_ARM64_SVE - HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, HWCAP_SVE), + HWCAP_CAP(SYS_ID_AA64PFR0_EL1, ID_AA64PFR0_SVE_SHIFT, FTR_UNSIGNED, ID_AA64PFR0_SVE, CAP_HWCAP, KERNEL_HWCAP_SVE), #endif - HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, HWCAP_SSBS), + HWCAP_CAP(SYS_ID_AA64PFR1_EL1, ID_AA64PFR1_SSBS_SHIFT, FTR_UNSIGNED, ID_AA64PFR1_SSBS_PSTATE_INSNS, CAP_HWCAP, KERNEL_HWCAP_SSBS), #ifdef CONFIG_ARM64_PTR_AUTH - HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, HWCAP_PACA), - HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, HWCAP_PACG), + HWCAP_MULTI_CAP(ptr_auth_hwcap_addr_matches, CAP_HWCAP, KERNEL_HWCAP_PACA), + HWCAP_MULTI_CAP(ptr_auth_hwcap_gen_matches, CAP_HWCAP, KERNEL_HWCAP_PACG), #endif {}, }; @@ -1588,7 +1591,7 @@ static void __init cap_set_elf_hwcap(const struct arm64_cpu_capabilities *cap) { switch (cap->hwcap_type) { case CAP_HWCAP: - elf_hwcap |= cap->hwcap; + cpu_set_feature(cap->hwcap); break; #ifdef CONFIG_COMPAT case CAP_COMPAT_HWCAP: @@ -1611,7 +1614,7 @@ static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap) switch (cap->hwcap_type) { case CAP_HWCAP: - rc = (elf_hwcap & cap->hwcap) != 0; + rc = cpu_have_feature(cap->hwcap); break; #ifdef CONFIG_COMPAT case CAP_COMPAT_HWCAP: @@ -1632,7 +1635,7 @@ static bool cpus_have_elf_hwcap(const struct arm64_cpu_capabilities *cap) static void __init setup_elf_hwcaps(const struct arm64_cpu_capabilities *hwcaps) { /* We support emulation of accesses to CPU ID feature registers */ - elf_hwcap |= HWCAP_CPUID; + cpu_set_feature(KERNEL_HWCAP_CPUID); for (; hwcaps->matches; hwcaps++) if (hwcaps->matches(hwcaps, cpucap_default_scope(hwcaps))) cap_set_elf_hwcap(hwcaps); diff --git a/arch/arm64/kernel/cpuinfo.c b/arch/arm64/kernel/cpuinfo.c index ca0685f..810db95 100644 --- a/arch/arm64/kernel/cpuinfo.c +++ b/arch/arm64/kernel/cpuinfo.c @@ -167,7 +167,7 @@ static int c_show(struct seq_file *m, void *v) #endif /* CONFIG_COMPAT */ } else { for (j = 0; hwcap_str[j]; j++) - if (elf_hwcap & (1 << j)) + if (cpu_have_feature(j)) seq_printf(m, " %s", hwcap_str[j]); } seq_puts(m, "\n"); diff --git a/arch/arm64/kernel/fpsimd.c b/arch/arm64/kernel/fpsimd.c index 5ebe73b..f28837c 100644 --- a/arch/arm64/kernel/fpsimd.c +++ b/arch/arm64/kernel/fpsimd.c @@ -1258,14 +1258,14 @@ static inline void fpsimd_hotplug_init(void) { } */ static int __init fpsimd_init(void) { - if (elf_hwcap & HWCAP_FP) { + if (cpu_have_feature(KERNEL_HWCAP_FP)) { fpsimd_pm_init(); fpsimd_hotplug_init(); } else { pr_notice("Floating-point is not implemented\n"); } - if (!(elf_hwcap & HWCAP_ASIMD)) + if (!cpu_have_feature(KERNEL_HWCAP_ASIMD)) pr_notice("Advanced SIMD is not implemented\n"); return sve_sysctl_init(); diff --git a/drivers/clocksource/arm_arch_timer.c b/drivers/clocksource/arm_arch_timer.c index 9a7d4dc..5b2d56d 100644 --- a/drivers/clocksource/arm_arch_timer.c +++ b/drivers/clocksource/arm_arch_timer.c @@ -778,7 +778,11 @@ static void arch_timer_evtstrm_enable(int divider) cntkctl |= (divider << ARCH_TIMER_EVT_TRIGGER_SHIFT) | ARCH_TIMER_VIRT_EVT_EN; arch_timer_set_cntkctl(cntkctl); +#ifdef CONFIG_ARM64 + cpu_set_feature(KERNEL_HWCAP_EVTSTRM); +#else elf_hwcap |= HWCAP_EVTSTRM; +#endif #ifdef CONFIG_COMPAT compat_elf_hwcap |= COMPAT_HWCAP_EVTSTRM; #endif @@ -1000,7 +1004,11 @@ static int arch_timer_cpu_pm_notify(struct notifier_block *self, } else if (action == CPU_PM_ENTER_FAILED || action == CPU_PM_EXIT) { arch_timer_set_cntkctl(__this_cpu_read(saved_cntkctl)); +#ifdef CONFIG_ARM64 + if (cpu_have_feature(KERNEL_HWCAP_EVTSTRM)) +#else if (elf_hwcap & HWCAP_EVTSTRM) +#endif cpumask_set_cpu(smp_processor_id(), &evtstrm_available); } return NOTIFY_OK;
As we will exhaust the first 32 bits of ELF_HWCAP let's start exposing ELF_HWCAP2 to userspace. Whilst it's possible to use the remaining 32 bits of ELF_HWCAP, we prefer to expand into ELF_HWCAP2 in order to provide a consistent view to userspace between ILP32 and LP64. To reduce complexity and allow for future expansion, we now represent hwcaps in the kernel as ordinals and use a KERNEL_HWCAP_ prefix. This allows us to support automatic feature based module loading for all our hwcaps. We introduce cpu_set_feature to set hwcaps in the relevant elf_hwcapX variable which compliments the existing cpu_have_feature helper. These helpers allow us to clean up existing direct uses of elf_hwcap. Signed-off-by: Andrew Murray <andrew.murray@arm.com> --- arch/arm64/crypto/aes-ce-ccm-glue.c | 2 +- arch/arm64/crypto/aes-neonbs-glue.c | 2 +- arch/arm64/crypto/chacha-neon-glue.c | 2 +- arch/arm64/crypto/crct10dif-ce-glue.c | 2 +- arch/arm64/crypto/ghash-ce-glue.c | 6 +-- arch/arm64/crypto/nhpoly1305-neon-glue.c | 2 +- arch/arm64/crypto/sha256-glue.c | 4 +- arch/arm64/include/asm/cpufeature.h | 18 +++++++-- arch/arm64/include/asm/hwcap.h | 41 ++++++++++++++++++- arch/arm64/include/uapi/asm/hwcap.h | 2 +- arch/arm64/kernel/cpufeature.c | 69 +++++++++++++++++--------------- arch/arm64/kernel/cpuinfo.c | 2 +- arch/arm64/kernel/fpsimd.c | 4 +- drivers/clocksource/arm_arch_timer.c | 8 ++++ 14 files changed, 111 insertions(+), 53 deletions(-)