diff mbox series

[v2] PowerPC: Influence cpu/arch hwcap features via GLIBC_TUNABLES.

Message ID 20230630151500.506180-1-bmahi496@linux.ibm.com
State New
Headers show
Series [v2] PowerPC: Influence cpu/arch hwcap features via GLIBC_TUNABLES. | expand

Commit Message

develop--- via Libc-alpha June 30, 2023, 3:15 p.m. UTC
From: Mahesh Bodapati <mahesh.bodapati@ibm.com>

This patch enables the option to influence hwcaps used by PowerPC.
The environment variable, GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz....,
can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature xxx
and zzz, where the feature name is case-sensitive and has to match the ones
mentioned in the file{sysdeps/powerpc/dl-procinfo.c}.

Note that the tunable only handles the features which are really used
in the IFUNC selection.  All others are ignored as the values are only
used inside glibc.
---
 manual/tunables.texi                          |  5 +-
 sysdeps/powerpc/cpu-features.c                | 93 ++++++++++++++++++-
 sysdeps/powerpc/cpu-features.h                | 57 ++++++++++++
 sysdeps/powerpc/dl-tunables.list              |  3 +
 sysdeps/powerpc/hwcapinfo.c                   |  4 +
 .../powerpc32/power4/multiarch/init-arch.h    | 10 +-
 sysdeps/powerpc/powerpc64/dl-machine.h        |  2 -
 .../powerpc64/multiarch/ifunc-impl-list.c     |  7 +-
 8 files changed, 170 insertions(+), 11 deletions(-)

Comments

Rajalakshmi Srinivasaraghavan July 5, 2023, 10:02 p.m. UTC | #1
On 6/30/23 10:15 AM, bmahi496@linux.ibm.com wrote:
> From: Mahesh Bodapati <mahesh.bodapati@ibm.com>
>
> This patch enables the option to influence hwcaps used by PowerPC.
> The environment variable, GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,-zzz....,
> can be used to enable CPU/ARCH feature yyy, disable CPU/ARCH feature xxx
> and zzz, where the feature name is case-sensitive and has to match the ones
> mentioned in the file{sysdeps/powerpc/dl-procinfo.c}.
>
> Note that the tunable only handles the features which are really used
> in the IFUNC selection.  All others are ignored as the values are only
> used inside glibc.
> ---
>   manual/tunables.texi                          |  5 +-
>   sysdeps/powerpc/cpu-features.c                | 93 ++++++++++++++++++-
>   sysdeps/powerpc/cpu-features.h                | 57 ++++++++++++
>   sysdeps/powerpc/dl-tunables.list              |  3 +
>   sysdeps/powerpc/hwcapinfo.c                   |  4 +
>   .../powerpc32/power4/multiarch/init-arch.h    | 10 +-
>   sysdeps/powerpc/powerpc64/dl-machine.h        |  2 -
>   .../powerpc64/multiarch/ifunc-impl-list.c     |  7 +-
>   8 files changed, 170 insertions(+), 11 deletions(-)
>
> diff --git a/manual/tunables.texi b/manual/tunables.texi
> index 4ca0e42a11..776fd93fd9 100644
> --- a/manual/tunables.texi
> +++ b/manual/tunables.texi
> @@ -513,7 +513,10 @@ On s390x, the supported HWCAP and STFLE features can be found in
>   @code{sysdeps/s390/cpu-features.c}.  In addition the user can also set
>   a CPU arch-level like @code{z13} instead of single HWCAP and STFLE features.
>   
> -This tunable is specific to i386, x86-64 and s390x.
> +On powerpc, the supported HWCAP and HWCAP2 features can be found in
> +@code{sysdeps/powerpc/dl-procinfo.c}.
> +
> +This tunable is specific to i386, x86-64, s390x and powerpc.
>   @end deftp
>   
>   @deftp Tunable glibc.cpu.cached_memopt
> diff --git a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c
> index 0ef3cf89d2..1239a01928 100644
> --- a/sysdeps/powerpc/cpu-features.c
> +++ b/sysdeps/powerpc/cpu-features.c
> @@ -19,14 +19,105 @@
>   #include <stdint.h>
>   #include <cpu-features.h>
>   #include <elf/dl-tunables.h>
> +#include <unistd.h>
> +#include <string.h>
> +#define MEMCMP_DEFAULT memcmp
> +#define STRLEN_DEFAULT strlen
> +
> +static void
> +TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
> +{
> +  /* The current IFUNC selection is always using the most recent
> +     features which are available via AT_HWCAP or AT_HWCAP2.  But in
> +     some scenarios it is useful to adjust this selection.
> +
> +     The environment variable:
> +
> +     GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,....
> +
> +     Can be used to enable HWCAP/HWCAP2 feature yyy, disable HWCAP/HWCAP2
> +     feature xxx, where the feature name is case-sensitive and has to match
> +     the ones mentioned in the file{sysdeps/powerpc/dl-procinfo.c}. */
> +
> +  /* Copy the features from dl_powerpc_cpu_features, which contains the features
Looks like more than 80 characters length.
> +     provided by AT_HWCAP and AT_HWCAP2.  */
> +  struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features);
> +  const char *token = valp->strval;
> +  do
> +    {
> +      const char *token_end, *feature;
> +      bool disable;
> +      size_t token_len, i, feature_len;
> +      /* Find token separator or end of string.  */
> +      for (token_end = token; *token_end != ','; token_end++)
> +	if (*token_end == '\0')
> +	  break;
> +
> +      /* Determine feature.  */
> +      token_len = token_end - token;
> +      if (*token == '-')
> +	{
> +	  disable = true;
> +	  feature = token + 1;
> +	  feature_len = token_len - 1;
> +	}
> +      else
> +	{
> +	  disable = false;
> +	  feature = token;
> +	  feature_len = token_len;
> +	}
> +      for (i=0; hwcap_tunables[i].name != NULL; ++i)

Minor comment.  Space after =.

> +	{
> +	  /* Check the tunable name on the supported list.  */
> +	  if (STRLEN_DEFAULT (hwcap_tunables[i].name) == feature_len
> +	      && MEMCMP_DEFAULT (feature, hwcap_tunables[i].name, feature_len)
> +	      == 0)
> +	    {
> +	      /* Update the hwcap and hwcap2 bits.  */
> +	      if (disable)
> +		{
> +		  /* Id is 1 for hwcap2 tunable.  */
> +		  if (hwcap_tunables[i].id)
> +		    cpu_features->hwcap2 &= ~(hwcap_tunables[i].mask);
> +		  else
> +		    cpu_features->hwcap &= ~(hwcap_tunables[i].mask);
> +		}
> +	      else
> +		{
> +		  if (hwcap_tunables[i].id)
> +		    cpu_features->hwcap2 |= (hwcap_tunables[i].mask);
> +		  else
> +		    cpu_features->hwcap |= (hwcap_tunables[i].mask);
> +		}
> +	    }
> +	}
> +	token += token_len;
> +	/* ... and skip token separator for next round.  */
> +	if (*token == ',') token++;
> +    }
> +  while (*token != '\0');
> +}
>   
>   static inline void
> -init_cpu_features (struct cpu_features *cpu_features)
> +init_cpu_features (struct cpu_features *cpu_features, uint64_t hwcaps[])
>   {
> +  /* Fill the cpu_features with the supported hwcaps
> +     which are set by __tcb_parse_hwcap_and_convert_at_platform.  */
> +  cpu_features->hwcap = hwcaps[0];
> +  cpu_features->hwcap2 = hwcaps[1];
> +
>     /* Default is to use aligned memory access on optimized function unless
>        tunables is enable, since for this case user can explicit disable
>        unaligned optimizations.  */
>     int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t,
>   					NULL);
>     cpu_features->use_cached_memopt = (cached_memfunc > 0);
> +  TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *,
> +	       TUNABLE_CALLBACK (set_hwcaps));
> +
> +  /* Copy back the features after checking that no unsupported features
> +     were enabled by user.  */
> +  cpu_features->hwcap &= hwcaps[0];
> +  cpu_features->hwcap2 &= hwcaps[1];
>   }
> diff --git a/sysdeps/powerpc/cpu-features.h b/sysdeps/powerpc/cpu-features.h
> index d316dc3d64..6839c3085b 100644
> --- a/sysdeps/powerpc/cpu-features.h
> +++ b/sysdeps/powerpc/cpu-features.h
> @@ -19,10 +19,67 @@
>   # define __CPU_FEATURES_POWERPC_H
>   
>   #include <stdbool.h>
> +#include <sys/auxv.h>
>   
>   struct cpu_features
>   {
>     bool use_cached_memopt;
> +  unsigned long int hwcap;
> +  unsigned long int hwcap2;
> +};
> +
> +static const struct
> +{
> +  const char *name;
> +  int mask;
> +  bool id;
> +} hwcap_tunables[] = {
> +   /* AT_HWCAP tunable masks.  */
> +   { "4xxmac",           PPC_FEATURE_HAS_4xxMAC,                 0 },
> +   { "altivec",          PPC_FEATURE_HAS_ALTIVEC,                0 },
> +   { "arch_2_05",        PPC_FEATURE_ARCH_2_05,                  0 },
> +   { "arch_2_06",        PPC_FEATURE_ARCH_2_06,                  0 },
> +   { "archpmu",          PPC_FEATURE_PSERIES_PERFMON_COMPAT,     0 },
> +   { "booke",            PPC_FEATURE_BOOKE,                      0 },
> +   { "cellbe",           PPC_FEATURE_CELL_BE,                    0 },
> +   { "dfp",              PPC_FEATURE_HAS_DFP,                    0 },
> +   { "efpdouble",        PPC_FEATURE_HAS_EFP_DOUBLE,             0 },
> +   { "efpsingle",        PPC_FEATURE_HAS_EFP_SINGLE,             0 },
> +   { "fpu",              PPC_FEATURE_HAS_FPU,                    0 },
> +   { "ic_snoop",         PPC_FEATURE_ICACHE_SNOOP,               0 },
> +   { "mmu",              PPC_FEATURE_HAS_MMU,                    0 },
> +   { "notb",             PPC_FEATURE_NO_TB,                      0 },
> +   { "pa6t",             PPC_FEATURE_PA6T,                       0 },
> +   { "power4",           PPC_FEATURE_POWER4,                     0 },
> +   { "power5",           PPC_FEATURE_POWER5,                     0 },
> +   { "power5+",          PPC_FEATURE_POWER5_PLUS,                0 },
> +   { "power6x",          PPC_FEATURE_POWER6_EXT,                 0 },
> +   { "ppc32",            PPC_FEATURE_32,                         0 },
> +   { "ppc601",           PPC_FEATURE_601_INSTR,                  0 },
> +   { "ppc64",            PPC_FEATURE_64,                         0 },
> +   { "ppcle",            PPC_FEATURE_PPC_LE,                     0 },
> +   { "smt",              PPC_FEATURE_SMT,                        0 },
> +   { "spe",              PPC_FEATURE_HAS_SPE,                    0 },
> +   { "true_le",          PPC_FEATURE_TRUE_LE,                    0 },
> +   { "ucache",           PPC_FEATURE_UNIFIED_CACHE,              0 },
> +   { "vsx",              PPC_FEATURE_HAS_VSX,                    0 },
> +
> +   /* AT_HWCAP2 tunable masks.  */
> +   { "arch_2_07",        PPC_FEATURE2_ARCH_2_07,                 1 },
> +   { "dscr",             PPC_FEATURE2_HAS_DSCR,                  1 },
> +   { "ebb",              PPC_FEATURE2_HAS_EBB,                   1 },
> +   { "htm",              PPC_FEATURE2_HAS_HTM,                   1 },
> +   { "htm-nosc",         PPC_FEATURE2_HTM_NOSC,                  1 },
> +   { "htm-no-suspend",   PPC_FEATURE2_HTM_NO_SUSPEND,            1 },
> +   { "isel",             PPC_FEATURE2_HAS_ISEL,                  1 },
> +   { "tar",              PPC_FEATURE2_HAS_TAR,                   1 },
> +   { "vcrypto",          PPC_FEATURE2_HAS_VEC_CRYPTO,            1 },
> +   { "arch_3_00",        PPC_FEATURE2_ARCH_3_00,                 1 },
> +   { "ieee128",          PPC_FEATURE2_HAS_IEEE128,               1 },
> +   { "darn",             PPC_FEATURE2_DARN,                      1 },
> +   { "scv",              PPC_FEATURE2_SCV,                       1 },
> +   { "arch_3_1",         PPC_FEATURE2_ARCH_3_1,                  1 },
> +   { "mma",              PPC_FEATURE2_MMA,                       1 },
>   };
>   
>   #endif /* __CPU_FEATURES_H  */
> diff --git a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list
> index 87d6235c75..807b7f8013 100644
> --- a/sysdeps/powerpc/dl-tunables.list
> +++ b/sysdeps/powerpc/dl-tunables.list
> @@ -24,5 +24,8 @@ glibc {
>         maxval: 1
>         default: 0
>       }
> +    hwcaps {
> +      type: STRING
> +    }
>     }
>   }
> diff --git a/sysdeps/powerpc/hwcapinfo.c b/sysdeps/powerpc/hwcapinfo.c
> index e26e64d99e..f2c473c556 100644
> --- a/sysdeps/powerpc/hwcapinfo.c
> +++ b/sysdeps/powerpc/hwcapinfo.c
> @@ -19,6 +19,7 @@
>   #include <unistd.h>
>   #include <shlib-compat.h>
>   #include <dl-procinfo.h>
> +#include <cpu-features.c>
>   
>   tcbhead_t __tcb __attribute__ ((visibility ("hidden")));
>   
> @@ -63,6 +64,9 @@ __tcb_parse_hwcap_and_convert_at_platform (void)
>     else if (h1 & PPC_FEATURE_POWER5)
>       h1 |= PPC_FEATURE_POWER4;
>   
> +  uint64_t array_hwcaps[] = { h1, h2 };
> +  init_cpu_features (&GLRO(dl_powerpc_cpu_features), array_hwcaps);
> +
>     /* Consolidate both HWCAP and HWCAP2 into a single doubleword so that
>        we can read both in a single load later.  */
>     __tcb.hwcap = (h1 << 32) | (h2 & 0xffffffff);
> diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> index 3dd00e02ee..a0bbd12012 100644
> --- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> +++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
> @@ -16,6 +16,7 @@
>      <https://www.gnu.org/licenses/>.  */
>   
>   #include <ldsodefs.h>
> +#include <cpu-features.h>
>   
>   /* The code checks if _rtld_global_ro was realocated before trying to access
>      the dl_hwcap field. The assembly is to make the compiler not optimize the
> @@ -32,11 +33,12 @@
>   # define __GLRO(value)  GLRO(value)
>   #endif
>   
> -/* dl_hwcap contains only the latest supported ISA, the macro checks which is
> -   and fills the previous ones.  */
> +/* Get the hardware information post the tunables set , the macro checks
> +   it and fills the previous ones.  */
>   #define INIT_ARCH() \
> -  unsigned long int hwcap = __GLRO(dl_hwcap); 			\
> -  unsigned long int __attribute__((unused)) hwcap2 = __GLRO(dl_hwcap2); \
> +  const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features);	\
> +  unsigned long int hwcap = features->hwcap;				\
> +  unsigned long int __attribute__((unused)) hwcap2 = features->hwcap2; \
>     bool __attribute__((unused)) use_cached_memopt =		\
>       __GLRO(dl_powerpc_cpu_features.use_cached_memopt);		\
>     if (hwcap & PPC_FEATURE_ARCH_2_06)				\
> diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
> index 9b8943bc91..449208e86f 100644
> --- a/sysdeps/powerpc/powerpc64/dl-machine.h
> +++ b/sysdeps/powerpc/powerpc64/dl-machine.h
> @@ -27,7 +27,6 @@
>   #include <dl-tls.h>
>   #include <sysdep.h>
>   #include <hwcapinfo.h>
> -#include <cpu-features.c>
>   #include <dl-static-tls.h>
>   #include <dl-funcdesc.h>
>   #include <dl-machine-rel.h>
> @@ -297,7 +296,6 @@ static inline void __attribute__ ((unused))
>   dl_platform_init (void)
>   {
>     __tcb_parse_hwcap_and_convert_at_platform ();
> -  init_cpu_features (&GLRO(dl_powerpc_cpu_features));
>   }
>   #endif
>   
> diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
> index ebe9434052..fc26dd0e17 100644
> --- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
> +++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c

Do we need to change powerpc32 ifunc-impl-list.c as well?

> @@ -17,6 +17,7 @@
>      <https://www.gnu.org/licenses/>.  */
>   
>   #include <assert.h>
> +#include <cpu-features.h>
>   #include <string.h>
>   #include <wchar.h>
>   #include <ldsodefs.h>
> @@ -27,9 +28,9 @@ __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
>   			size_t max)
>   {
>     size_t i = max;
> -
> -  unsigned long int hwcap = GLRO(dl_hwcap);
> -  unsigned long int hwcap2 = GLRO(dl_hwcap2);
> +  const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features);
> +  unsigned long int hwcap = features->hwcap;
> +  unsigned long int hwcap2 = features->hwcap2;
>   #ifdef SHARED
>     int cacheline_size = GLRO(dl_cache_line_size);
>   #endif

LGTM.
diff mbox series

Patch

diff --git a/manual/tunables.texi b/manual/tunables.texi
index 4ca0e42a11..776fd93fd9 100644
--- a/manual/tunables.texi
+++ b/manual/tunables.texi
@@ -513,7 +513,10 @@  On s390x, the supported HWCAP and STFLE features can be found in
 @code{sysdeps/s390/cpu-features.c}.  In addition the user can also set
 a CPU arch-level like @code{z13} instead of single HWCAP and STFLE features.
 
-This tunable is specific to i386, x86-64 and s390x.
+On powerpc, the supported HWCAP and HWCAP2 features can be found in
+@code{sysdeps/powerpc/dl-procinfo.c}.
+
+This tunable is specific to i386, x86-64, s390x and powerpc.
 @end deftp
 
 @deftp Tunable glibc.cpu.cached_memopt
diff --git a/sysdeps/powerpc/cpu-features.c b/sysdeps/powerpc/cpu-features.c
index 0ef3cf89d2..1239a01928 100644
--- a/sysdeps/powerpc/cpu-features.c
+++ b/sysdeps/powerpc/cpu-features.c
@@ -19,14 +19,105 @@ 
 #include <stdint.h>
 #include <cpu-features.h>
 #include <elf/dl-tunables.h>
+#include <unistd.h>
+#include <string.h>
+#define MEMCMP_DEFAULT memcmp
+#define STRLEN_DEFAULT strlen
+
+static void
+TUNABLE_CALLBACK (set_hwcaps) (tunable_val_t *valp)
+{
+  /* The current IFUNC selection is always using the most recent
+     features which are available via AT_HWCAP or AT_HWCAP2.  But in
+     some scenarios it is useful to adjust this selection.
+
+     The environment variable:
+
+     GLIBC_TUNABLES=glibc.cpu.hwcaps=-xxx,yyy,....
+
+     Can be used to enable HWCAP/HWCAP2 feature yyy, disable HWCAP/HWCAP2
+     feature xxx, where the feature name is case-sensitive and has to match
+     the ones mentioned in the file{sysdeps/powerpc/dl-procinfo.c}. */
+
+  /* Copy the features from dl_powerpc_cpu_features, which contains the features
+     provided by AT_HWCAP and AT_HWCAP2.  */
+  struct cpu_features *cpu_features = &GLRO(dl_powerpc_cpu_features);
+  const char *token = valp->strval;
+  do
+    {
+      const char *token_end, *feature;
+      bool disable;
+      size_t token_len, i, feature_len;
+      /* Find token separator or end of string.  */
+      for (token_end = token; *token_end != ','; token_end++)
+	if (*token_end == '\0')
+	  break;
+
+      /* Determine feature.  */
+      token_len = token_end - token;
+      if (*token == '-')
+	{
+	  disable = true;
+	  feature = token + 1;
+	  feature_len = token_len - 1;
+	}
+      else
+	{
+	  disable = false;
+	  feature = token;
+	  feature_len = token_len;
+	}
+      for (i=0; hwcap_tunables[i].name != NULL; ++i)
+	{
+	  /* Check the tunable name on the supported list.  */
+	  if (STRLEN_DEFAULT (hwcap_tunables[i].name) == feature_len
+	      && MEMCMP_DEFAULT (feature, hwcap_tunables[i].name, feature_len)
+	      == 0)
+	    {
+	      /* Update the hwcap and hwcap2 bits.  */
+	      if (disable)
+		{
+		  /* Id is 1 for hwcap2 tunable.  */
+		  if (hwcap_tunables[i].id)
+		    cpu_features->hwcap2 &= ~(hwcap_tunables[i].mask);
+		  else
+		    cpu_features->hwcap &= ~(hwcap_tunables[i].mask);
+		}
+	      else
+		{
+		  if (hwcap_tunables[i].id)
+		    cpu_features->hwcap2 |= (hwcap_tunables[i].mask);
+		  else
+		    cpu_features->hwcap |= (hwcap_tunables[i].mask);
+		}
+	    }
+	}
+	token += token_len;
+	/* ... and skip token separator for next round.  */
+	if (*token == ',') token++;
+    }
+  while (*token != '\0');
+}
 
 static inline void
-init_cpu_features (struct cpu_features *cpu_features)
+init_cpu_features (struct cpu_features *cpu_features, uint64_t hwcaps[])
 {
+  /* Fill the cpu_features with the supported hwcaps
+     which are set by __tcb_parse_hwcap_and_convert_at_platform.  */
+  cpu_features->hwcap = hwcaps[0];
+  cpu_features->hwcap2 = hwcaps[1];
+
   /* Default is to use aligned memory access on optimized function unless
      tunables is enable, since for this case user can explicit disable
      unaligned optimizations.  */
   int32_t cached_memfunc = TUNABLE_GET (glibc, cpu, cached_memopt, int32_t,
 					NULL);
   cpu_features->use_cached_memopt = (cached_memfunc > 0);
+  TUNABLE_GET (glibc, cpu, hwcaps, tunable_val_t *,
+	       TUNABLE_CALLBACK (set_hwcaps));
+
+  /* Copy back the features after checking that no unsupported features
+     were enabled by user.  */
+  cpu_features->hwcap &= hwcaps[0];
+  cpu_features->hwcap2 &= hwcaps[1];
 }
diff --git a/sysdeps/powerpc/cpu-features.h b/sysdeps/powerpc/cpu-features.h
index d316dc3d64..6839c3085b 100644
--- a/sysdeps/powerpc/cpu-features.h
+++ b/sysdeps/powerpc/cpu-features.h
@@ -19,10 +19,67 @@ 
 # define __CPU_FEATURES_POWERPC_H
 
 #include <stdbool.h>
+#include <sys/auxv.h>
 
 struct cpu_features
 {
   bool use_cached_memopt;
+  unsigned long int hwcap;
+  unsigned long int hwcap2;
+};
+
+static const struct
+{
+  const char *name;
+  int mask;
+  bool id;
+} hwcap_tunables[] = {
+   /* AT_HWCAP tunable masks.  */
+   { "4xxmac",           PPC_FEATURE_HAS_4xxMAC,                 0 },
+   { "altivec",          PPC_FEATURE_HAS_ALTIVEC,                0 },
+   { "arch_2_05",        PPC_FEATURE_ARCH_2_05,                  0 },
+   { "arch_2_06",        PPC_FEATURE_ARCH_2_06,                  0 },
+   { "archpmu",          PPC_FEATURE_PSERIES_PERFMON_COMPAT,     0 },
+   { "booke",            PPC_FEATURE_BOOKE,                      0 },
+   { "cellbe",           PPC_FEATURE_CELL_BE,                    0 },
+   { "dfp",              PPC_FEATURE_HAS_DFP,                    0 },
+   { "efpdouble",        PPC_FEATURE_HAS_EFP_DOUBLE,             0 },
+   { "efpsingle",        PPC_FEATURE_HAS_EFP_SINGLE,             0 },
+   { "fpu",              PPC_FEATURE_HAS_FPU,                    0 },
+   { "ic_snoop",         PPC_FEATURE_ICACHE_SNOOP,               0 },
+   { "mmu",              PPC_FEATURE_HAS_MMU,                    0 },
+   { "notb",             PPC_FEATURE_NO_TB,                      0 },
+   { "pa6t",             PPC_FEATURE_PA6T,                       0 },
+   { "power4",           PPC_FEATURE_POWER4,                     0 },
+   { "power5",           PPC_FEATURE_POWER5,                     0 },
+   { "power5+",          PPC_FEATURE_POWER5_PLUS,                0 },
+   { "power6x",          PPC_FEATURE_POWER6_EXT,                 0 },
+   { "ppc32",            PPC_FEATURE_32,                         0 },
+   { "ppc601",           PPC_FEATURE_601_INSTR,                  0 },
+   { "ppc64",            PPC_FEATURE_64,                         0 },
+   { "ppcle",            PPC_FEATURE_PPC_LE,                     0 },
+   { "smt",              PPC_FEATURE_SMT,                        0 },
+   { "spe",              PPC_FEATURE_HAS_SPE,                    0 },
+   { "true_le",          PPC_FEATURE_TRUE_LE,                    0 },
+   { "ucache",           PPC_FEATURE_UNIFIED_CACHE,              0 },
+   { "vsx",              PPC_FEATURE_HAS_VSX,                    0 },
+
+   /* AT_HWCAP2 tunable masks.  */
+   { "arch_2_07",        PPC_FEATURE2_ARCH_2_07,                 1 },
+   { "dscr",             PPC_FEATURE2_HAS_DSCR,                  1 },
+   { "ebb",              PPC_FEATURE2_HAS_EBB,                   1 },
+   { "htm",              PPC_FEATURE2_HAS_HTM,                   1 },
+   { "htm-nosc",         PPC_FEATURE2_HTM_NOSC,                  1 },
+   { "htm-no-suspend",   PPC_FEATURE2_HTM_NO_SUSPEND,            1 },
+   { "isel",             PPC_FEATURE2_HAS_ISEL,                  1 },
+   { "tar",              PPC_FEATURE2_HAS_TAR,                   1 },
+   { "vcrypto",          PPC_FEATURE2_HAS_VEC_CRYPTO,            1 },
+   { "arch_3_00",        PPC_FEATURE2_ARCH_3_00,                 1 },
+   { "ieee128",          PPC_FEATURE2_HAS_IEEE128,               1 },
+   { "darn",             PPC_FEATURE2_DARN,                      1 },
+   { "scv",              PPC_FEATURE2_SCV,                       1 },
+   { "arch_3_1",         PPC_FEATURE2_ARCH_3_1,                  1 },
+   { "mma",              PPC_FEATURE2_MMA,                       1 },
 };
 
 #endif /* __CPU_FEATURES_H  */
diff --git a/sysdeps/powerpc/dl-tunables.list b/sysdeps/powerpc/dl-tunables.list
index 87d6235c75..807b7f8013 100644
--- a/sysdeps/powerpc/dl-tunables.list
+++ b/sysdeps/powerpc/dl-tunables.list
@@ -24,5 +24,8 @@  glibc {
       maxval: 1
       default: 0
     }
+    hwcaps {
+      type: STRING
+    }
   }
 }
diff --git a/sysdeps/powerpc/hwcapinfo.c b/sysdeps/powerpc/hwcapinfo.c
index e26e64d99e..f2c473c556 100644
--- a/sysdeps/powerpc/hwcapinfo.c
+++ b/sysdeps/powerpc/hwcapinfo.c
@@ -19,6 +19,7 @@ 
 #include <unistd.h>
 #include <shlib-compat.h>
 #include <dl-procinfo.h>
+#include <cpu-features.c>
 
 tcbhead_t __tcb __attribute__ ((visibility ("hidden")));
 
@@ -63,6 +64,9 @@  __tcb_parse_hwcap_and_convert_at_platform (void)
   else if (h1 & PPC_FEATURE_POWER5)
     h1 |= PPC_FEATURE_POWER4;
 
+  uint64_t array_hwcaps[] = { h1, h2 };
+  init_cpu_features (&GLRO(dl_powerpc_cpu_features), array_hwcaps);
+
   /* Consolidate both HWCAP and HWCAP2 into a single doubleword so that
      we can read both in a single load later.  */
   __tcb.hwcap = (h1 << 32) | (h2 & 0xffffffff);
diff --git a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
index 3dd00e02ee..a0bbd12012 100644
--- a/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
+++ b/sysdeps/powerpc/powerpc32/power4/multiarch/init-arch.h
@@ -16,6 +16,7 @@ 
    <https://www.gnu.org/licenses/>.  */
 
 #include <ldsodefs.h>
+#include <cpu-features.h>
 
 /* The code checks if _rtld_global_ro was realocated before trying to access
    the dl_hwcap field. The assembly is to make the compiler not optimize the
@@ -32,11 +33,12 @@ 
 # define __GLRO(value)  GLRO(value)
 #endif
 
-/* dl_hwcap contains only the latest supported ISA, the macro checks which is
-   and fills the previous ones.  */
+/* Get the hardware information post the tunables set , the macro checks
+   it and fills the previous ones.  */
 #define INIT_ARCH() \
-  unsigned long int hwcap = __GLRO(dl_hwcap); 			\
-  unsigned long int __attribute__((unused)) hwcap2 = __GLRO(dl_hwcap2); \
+  const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features);	\
+  unsigned long int hwcap = features->hwcap;				\
+  unsigned long int __attribute__((unused)) hwcap2 = features->hwcap2; \
   bool __attribute__((unused)) use_cached_memopt =		\
     __GLRO(dl_powerpc_cpu_features.use_cached_memopt);		\
   if (hwcap & PPC_FEATURE_ARCH_2_06)				\
diff --git a/sysdeps/powerpc/powerpc64/dl-machine.h b/sysdeps/powerpc/powerpc64/dl-machine.h
index 9b8943bc91..449208e86f 100644
--- a/sysdeps/powerpc/powerpc64/dl-machine.h
+++ b/sysdeps/powerpc/powerpc64/dl-machine.h
@@ -27,7 +27,6 @@ 
 #include <dl-tls.h>
 #include <sysdep.h>
 #include <hwcapinfo.h>
-#include <cpu-features.c>
 #include <dl-static-tls.h>
 #include <dl-funcdesc.h>
 #include <dl-machine-rel.h>
@@ -297,7 +296,6 @@  static inline void __attribute__ ((unused))
 dl_platform_init (void)
 {
   __tcb_parse_hwcap_and_convert_at_platform ();
-  init_cpu_features (&GLRO(dl_powerpc_cpu_features));
 }
 #endif
 
diff --git a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
index ebe9434052..fc26dd0e17 100644
--- a/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
+++ b/sysdeps/powerpc/powerpc64/multiarch/ifunc-impl-list.c
@@ -17,6 +17,7 @@ 
    <https://www.gnu.org/licenses/>.  */
 
 #include <assert.h>
+#include <cpu-features.h>
 #include <string.h>
 #include <wchar.h>
 #include <ldsodefs.h>
@@ -27,9 +28,9 @@  __libc_ifunc_impl_list (const char *name, struct libc_ifunc_impl *array,
 			size_t max)
 {
   size_t i = max;
-
-  unsigned long int hwcap = GLRO(dl_hwcap);
-  unsigned long int hwcap2 = GLRO(dl_hwcap2);
+  const struct cpu_features *features = &GLRO(dl_powerpc_cpu_features);
+  unsigned long int hwcap = features->hwcap;
+  unsigned long int hwcap2 = features->hwcap2;
 #ifdef SHARED
   int cacheline_size = GLRO(dl_cache_line_size);
 #endif