diff mbox series

[v2,3/6] arm64: HWCAP: encapsulate elf_hwcap

Message ID 1550751657-30252-4-git-send-email-andrew.murray@arm.com (mailing list archive)
State New, archived
Headers show
Series Initial support for CVADP | expand

Commit Message

Andrew Murray Feb. 21, 2019, 12:20 p.m. UTC
The introduction of AT_HWCAP2 introduced accessors which ensure that
hwcap features are set and tested appropriately.

Let's now mandate access to elf_hwcap via these accessors by making
elf_hwcap static within cpufeature.c.

Signed-off-by: Andrew Murray <andrew.murray@arm.com>
---
 arch/arm64/include/asm/cpufeature.h | 15 ++++-----------
 arch/arm64/include/asm/hwcap.h      |  6 +++---
 arch/arm64/kernel/cpufeature.c      | 27 +++++++++++++++++++++++++--
 3 files changed, 32 insertions(+), 16 deletions(-)

Comments

Dave Martin Feb. 21, 2019, 6:45 p.m. UTC | #1
On Thu, Feb 21, 2019 at 12:20:54PM +0000, Andrew Murray wrote:
> The introduction of AT_HWCAP2 introduced accessors which ensure that
> hwcap features are set and tested appropriately.
>
> Let's now mandate access to elf_hwcap via these accessors by making
> elf_hwcap static within cpufeature.c.

Since elf_hwcap now survives and retains a compatible encoding for
HWCAP_foo, I'm wondering whether it would be simpler to drop this patch.

Although this will help push people to use the new helpers, the need to
do that seems reduced now.

People falling off the end of the hwcaps will discover that there is no
HWCAP_foo for the feature they want, only HWCAP2_foo (but no elf_hwcap2
to look for it in), or KERNEL_HWCAP_foo (which should get them
thinking).

What do you think?

[...]

> diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> index 6a477a3..d57a179 100644
> --- a/arch/arm64/kernel/cpufeature.c
> +++ b/arch/arm64/kernel/cpufeature.c
> @@ -35,8 +35,7 @@
>  #include <asm/traps.h>
>  #include <asm/virt.h>
>
> -unsigned long elf_hwcap __read_mostly;
> -EXPORT_SYMBOL_GPL(elf_hwcap);
> +static unsigned long elf_hwcap __read_mostly;
>
>  #ifdef CONFIG_COMPAT
>  #define COMPAT_ELF_HWCAP_DEFAULT\
> @@ -1909,6 +1908,30 @@ bool this_cpu_has_cap(unsigned int n)
>  return false;
>  }
>
> +void cpu_set_feature(unsigned int num)
> +{
> +WARN_ON(num >= MAX_CPU_FEATURES);
> +elf_hwcap |= BIT(num);
> +}
> +EXPORT_SYMBOL_GPL(cpu_set_feature);
> +
> +bool cpu_have_feature(unsigned int num)
> +{
> +WARN_ON(num >= MAX_CPU_FEATURES);
> +return elf_hwcap & BIT(num);
> +}
> +EXPORT_SYMBOL_GPL(cpu_have_feature);
> +
> +unsigned long cpu_get_elf_hwcap(void)
> +{
> +return lower_32_bits(elf_hwcap);
> +}
> +
> +unsigned long cpu_get_elf_hwcap2(void)
> +{
> +return upper_32_bits(elf_hwcap);
> +}
> +

Similarly, pushing all this out of line to enable elf_hwcap to be hidden
may be more effort than it is really worth (?)

Cheers
---Dave
IMPORTANT NOTICE: The contents of this email and any attachments are confidential and may also be privileged. If you are not the intended recipient, please notify the sender immediately and do not disclose the contents to any other person, use it for any purpose, or store or copy the information in any medium. Thank you.
Andrew Murray March 27, 2019, 2:03 p.m. UTC | #2
On Thu, Feb 21, 2019 at 06:45:08PM +0000, Dave P Martin wrote:
> On Thu, Feb 21, 2019 at 12:20:54PM +0000, Andrew Murray wrote:
> > The introduction of AT_HWCAP2 introduced accessors which ensure that
> > hwcap features are set and tested appropriately.
> > 
> > Let's now mandate access to elf_hwcap via these accessors by making
> > elf_hwcap static within cpufeature.c.
> 
> Since elf_hwcap now survives and retains a compatible encoding for
> HWCAP_foo, I'm wondering whether it would be simpler to drop this patch.
> 
> Although this will help push people to use the new helpers, the need to
> do that seems reduced now.
> 
> People falling off the end of the hwcaps will discover that there is no
> HWCAP_foo for the feature they want, only HWCAP2_foo (but no elf_hwcap2
> to look for it in), or KERNEL_HWCAP_foo (which should get them
> thinking).
> 
> What do you think?

You're right that people will find the appropiate functions to set the
relevant hwcaps. But I think my motivation for this comes from the
perspective of code maintainability...

There is absolutely no functional benefit to exposing the elf_hwcap
variable to the rest of the kernel - yet doing so will result in users
using elf_hwcap instead of the helpers. If we later change the type of
elf_hwcap, or split the bits into multiple variables (e.g. elf_hwcap2) or
even change the mapping from UAPI to kernel, then modifications need to be
made at each call site. Whereas if we reduce the visibility of elf_hwcap
then we encapsulate all the bit fiddling in one place.

Also, taking this approach forces us into this ugly suitation...

+#ifdef CONFIG_ARM64
+               if (cpu_have_feature_name(EVTSTRM))
+#else
                if (elf_hwcap & HWCAP_EVTSTRM)
+#endif

It's not nice, but it's a lot less fragile than expecting cross-platform
agreement on the bit value of particular hwcaps.

Is this a good enough reason to keep it?

Thanks,

Andrew Murray

> 
> [...]
> 
> > diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
> > index 6a477a3..d57a179 100644
> > --- a/arch/arm64/kernel/cpufeature.c
> > +++ b/arch/arm64/kernel/cpufeature.c
> > @@ -35,8 +35,7 @@
> >  #include <asm/traps.h>
> >  #include <asm/virt.h>
> >  
> > -unsigned long elf_hwcap __read_mostly;
> > -EXPORT_SYMBOL_GPL(elf_hwcap);
> > +static unsigned long elf_hwcap __read_mostly;
> >  
> >  #ifdef CONFIG_COMPAT
> >  #define COMPAT_ELF_HWCAP_DEFAULT	\
> > @@ -1909,6 +1908,30 @@ bool this_cpu_has_cap(unsigned int n)
> >  	return false;
> >  }
> >  
> > +void cpu_set_feature(unsigned int num)
> > +{
> > +	WARN_ON(num >= MAX_CPU_FEATURES);
> > +	elf_hwcap |= BIT(num);
> > +}
> > +EXPORT_SYMBOL_GPL(cpu_set_feature);
> > +
> > +bool cpu_have_feature(unsigned int num)
> > +{
> > +	WARN_ON(num >= MAX_CPU_FEATURES);
> > +	return elf_hwcap & BIT(num);
> > +}
> > +EXPORT_SYMBOL_GPL(cpu_have_feature);
> > +
> > +unsigned long cpu_get_elf_hwcap(void)
> > +{
> > +	return lower_32_bits(elf_hwcap);
> > +}
> > +
> > +unsigned long cpu_get_elf_hwcap2(void)
> > +{
> > +	return upper_32_bits(elf_hwcap);
> > +}
> > +
> 
> Similarly, pushing all this out of line to enable elf_hwcap to be hidden
> may be more effort than it is really worth (?)
> 
> Cheers
> ---Dave
Dave Martin March 28, 2019, 11:32 a.m. UTC | #3
On Wed, Mar 27, 2019 at 02:03:11PM +0000, Andrew Murray wrote:
> On Thu, Feb 21, 2019 at 06:45:08PM +0000, Dave P Martin wrote:
> > On Thu, Feb 21, 2019 at 12:20:54PM +0000, Andrew Murray wrote:
> > > The introduction of AT_HWCAP2 introduced accessors which ensure that
> > > hwcap features are set and tested appropriately.
> > > 
> > > Let's now mandate access to elf_hwcap via these accessors by making
> > > elf_hwcap static within cpufeature.c.
> > 
> > Since elf_hwcap now survives and retains a compatible encoding for
> > HWCAP_foo, I'm wondering whether it would be simpler to drop this patch.
> > 
> > Although this will help push people to use the new helpers, the need to
> > do that seems reduced now.
> > 
> > People falling off the end of the hwcaps will discover that there is no
> > HWCAP_foo for the feature they want, only HWCAP2_foo (but no elf_hwcap2
> > to look for it in), or KERNEL_HWCAP_foo (which should get them
> > thinking).
> > 
> > What do you think?
> 
> You're right that people will find the appropiate functions to set the
> relevant hwcaps. But I think my motivation for this comes from the
> perspective of code maintainability...
> 
> There is absolutely no functional benefit to exposing the elf_hwcap
> variable to the rest of the kernel - yet doing so will result in users
> using elf_hwcap instead of the helpers. If we later change the type of
> elf_hwcap, or split the bits into multiple variables (e.g. elf_hwcap2) or
> even change the mapping from UAPI to kernel, then modifications need to be
> made at each call site. Whereas if we reduce the visibility of elf_hwcap
> then we encapsulate all the bit fiddling in one place.
> 
> Also, taking this approach forces us into this ugly suitation...
> 
> +#ifdef CONFIG_ARM64
> +               if (cpu_have_feature_name(EVTSTRM))
> +#else
>                 if (elf_hwcap & HWCAP_EVTSTRM)
> +#endif
> 
> It's not nice, but it's a lot less fragile than expecting cross-platform
> agreement on the bit value of particular hwcaps.
> 
> Is this a good enough reason to keep it?

Yes, I'm happy for us to go forward with your approach here.  Although
it makes a bit more diff noise now, I agree it's the cleaner option for
the future.

Cheers
---Dave
diff mbox series

Patch

diff --git a/arch/arm64/include/asm/cpufeature.h b/arch/arm64/include/asm/cpufeature.h
index dd21a32..a5acce4 100644
--- a/arch/arm64/include/asm/cpufeature.h
+++ b/arch/arm64/include/asm/cpufeature.h
@@ -395,19 +395,12 @@  extern struct static_key_false arm64_const_caps_ready;
 	for_each_set_bit(cap, cpu_hwcaps, ARM64_NCAPS)
 
 bool this_cpu_has_cap(unsigned int cap);
+void cpu_set_feature(unsigned int num);
+bool cpu_have_feature(unsigned int num);
+unsigned long cpu_get_elf_hwcap(void);
+unsigned long cpu_get_elf_hwcap2(void);
 
-static inline void cpu_set_feature(unsigned int num)
-{
-	WARN_ON(num >= MAX_CPU_FEATURES);
-	elf_hwcap |= BIT(num);
-}
 #define cpu_set_feature_name(name) cpu_set_feature(cpu_feature(name))
-
-static inline bool cpu_have_feature(unsigned int num)
-{
-	WARN_ON(num >= MAX_CPU_FEATURES);
-	return elf_hwcap & BIT(num);
-}
 #define cpu_have_feature_name(name) cpu_have_feature(cpu_feature(name))
 
 /* System capability check for constant caps */
diff --git a/arch/arm64/include/asm/hwcap.h b/arch/arm64/include/asm/hwcap.h
index 7549c72..170fb94 100644
--- a/arch/arm64/include/asm/hwcap.h
+++ b/arch/arm64/include/asm/hwcap.h
@@ -17,6 +17,7 @@ 
 #define __ASM_HWCAP_H
 
 #include <uapi/asm/hwcap.h>
+#include <asm/cpufeature.h>
 
 #define COMPAT_HWCAP_HALF	(1 << 1)
 #define COMPAT_HWCAP_THUMB	(1 << 2)
@@ -81,8 +82,8 @@ 
  * This yields a mask that user programs can use to figure out what
  * instruction set this cpu supports.
  */
-#define ELF_HWCAP		lower_32_bits(elf_hwcap)
-#define ELF_HWCAP2		upper_32_bits(elf_hwcap)
+#define ELF_HWCAP		cpu_get_elf_hwcap()
+#define ELF_HWCAP2		cpu_get_elf_hwcap2()
 
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP	(compat_elf_hwcap)
@@ -98,6 +99,5 @@  enum {
 #endif
 };
 
-extern unsigned long elf_hwcap;
 #endif
 #endif
diff --git a/arch/arm64/kernel/cpufeature.c b/arch/arm64/kernel/cpufeature.c
index 6a477a3..d57a179 100644
--- a/arch/arm64/kernel/cpufeature.c
+++ b/arch/arm64/kernel/cpufeature.c
@@ -35,8 +35,7 @@ 
 #include <asm/traps.h>
 #include <asm/virt.h>
 
-unsigned long elf_hwcap __read_mostly;
-EXPORT_SYMBOL_GPL(elf_hwcap);
+static unsigned long elf_hwcap __read_mostly;
 
 #ifdef CONFIG_COMPAT
 #define COMPAT_ELF_HWCAP_DEFAULT	\
@@ -1909,6 +1908,30 @@  bool this_cpu_has_cap(unsigned int n)
 	return false;
 }
 
+void cpu_set_feature(unsigned int num)
+{
+	WARN_ON(num >= MAX_CPU_FEATURES);
+	elf_hwcap |= BIT(num);
+}
+EXPORT_SYMBOL_GPL(cpu_set_feature);
+
+bool cpu_have_feature(unsigned int num)
+{
+	WARN_ON(num >= MAX_CPU_FEATURES);
+	return elf_hwcap & BIT(num);
+}
+EXPORT_SYMBOL_GPL(cpu_have_feature);
+
+unsigned long cpu_get_elf_hwcap(void)
+{
+	return lower_32_bits(elf_hwcap);
+}
+
+unsigned long cpu_get_elf_hwcap2(void)
+{
+	return upper_32_bits(elf_hwcap);
+}
+
 static void __init setup_system_capabilities(void)
 {
 	/*