diff --git a/config.h.in b/config.h.in
index 2caa412..47b139e 100644
--- a/config.h.in
+++ b/config.h.in
@@ -147,9 +147,6 @@
 /* Define if __stack_chk_guard canary should be randomized at program startup.  */
 #undef ENABLE_STACKGUARD_RANDOMIZE
 
-/* Define if lock elision should be enabled by default.  */
-#undef ENABLE_LOCK_ELISION
-
 /* Package description.  */
 #undef PKGVERSION
 
diff --git a/configure b/configure
index 422482f..d3b68c1 100755
--- a/configure
+++ b/configure
@@ -677,7 +677,6 @@ enable_werror
 all_warnings
 force_install
 bindnow
-enable_lock_elision
 hardcoded_path_in_tests
 enable_timezone_tools
 use_default_link
@@ -766,7 +765,6 @@ enable_profile
 enable_timezone_tools
 enable_hardcoded_path_in_tests
 enable_stackguard_randomization
-enable_lock_elision
 enable_add_ons
 enable_hidden_plt
 enable_bind_now
@@ -1427,8 +1425,6 @@ Optional Features:
   --enable-stackguard-randomization
                           initialize __stack_chk_guard canary with a random
                           number at program start
-  --enable-lock-elision=yes/no
-                          Enable lock elision for pthread mutexes by default
   --enable-add-ons[=DIRS...]
                           configure and build add-ons in DIR1,DIR2,... search
                           for add-ons if no parameter given
@@ -3395,19 +3391,6 @@ if test "$enable_stackguard_randomize" = yes; then
 
 fi
 
-# Check whether --enable-lock-elision was given.
-if test "${enable_lock_elision+set}" = set; then :
-  enableval=$enable_lock_elision; enable_lock_elision=$enableval
-else
-  enable_lock_elision=no
-fi
-
-
-if test "$enable_lock_elision" = yes ; then
-  $as_echo "#define ENABLE_LOCK_ELISION 1" >>confdefs.h
-
-fi
-
 # Check whether --enable-add-ons was given.
 if test "${enable_add_ons+set}" = set; then :
   enableval=$enable_add_ons;
diff --git a/configure.ac b/configure.ac
index 7f43042..a970296 100644
--- a/configure.ac
+++ b/configure.ac
@@ -199,16 +199,6 @@ if test "$enable_stackguard_randomize" = yes; then
   AC_DEFINE(ENABLE_STACKGUARD_RANDOMIZE)
 fi
 
-AC_ARG_ENABLE([lock-elision],
-	      AC_HELP_STRING([--enable-lock-elision[=yes/no]],
-			     [Enable lock elision for pthread mutexes by default]),
-	      [enable_lock_elision=$enableval],
-	      [enable_lock_elision=no])
-AC_SUBST(enable_lock_elision)
-if test "$enable_lock_elision" = yes ; then
-  AC_DEFINE(ENABLE_LOCK_ELISION)
-fi
-
 dnl Generic infrastructure for drop-in additions to libc.
 AC_ARG_ENABLE([add-ons],
 	      AC_HELP_STRING([--enable-add-ons@<:@=DIRS...@:>@],
diff --git a/elf/dl-tunables.h b/elf/dl-tunables.h
index f33adfb..3dad518 100644
--- a/elf/dl-tunables.h
+++ b/elf/dl-tunables.h
@@ -18,8 +18,8 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifndef _TUNABLES_H_
-#define _TUNABLES_H_
+#ifndef _DL_TUNABLES_H_
+#define _DL_TUNABLES_H_
 
 #if !HAVE_TUNABLES
 static inline void
diff --git a/elf/dl-tunables.list b/elf/dl-tunables.list
index b9f1488..97062f9 100644
--- a/elf/dl-tunables.list
+++ b/elf/dl-tunables.list
@@ -77,4 +77,12 @@ glibc {
       security_level: SXID_IGNORE
     }
   }
+  elision {
+    enable {
+      type: INT_32
+      minval: 0
+      maxval: 1
+      security_level: SXID_IGNORE
+    }
+  }
 }
diff --git a/nptl/Makefile b/nptl/Makefile
index 6d48c0c..a720612 100644
--- a/nptl/Makefile
+++ b/nptl/Makefile
@@ -704,6 +704,10 @@ $(objpfx)tst-oddstacklimit.out: $(objpfx)tst-oddstacklimit $(objpfx)tst-basic1
 	$(evaluate-test)
 endif
 
+# Disable elision for tst-mutex8 so it can verify error case for
+# destroying a mutex.
+tst-mutex8-ENV = GLIBC_TUNABLES=glibc.elision.enable=0
+
 # The tests here better do not run in parallel
 ifneq ($(filter %tests,$(MAKECMDGOALS)),)
 .NOTPARALLEL:
diff --git a/nptl/tst-mutex8.c b/nptl/tst-mutex8.c
index 1d288d2..ef59db5 100644
--- a/nptl/tst-mutex8.c
+++ b/nptl/tst-mutex8.c
@@ -127,9 +127,8 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
       return 1;
     }
 
-  /* Elided mutexes don't fail destroy. If elision is not explicitly disabled
-     we don't know, so can also not check this.  */
-#ifndef ENABLE_LOCK_ELISION
+  /* Elided mutexes don't fail destroy, but this test is run with
+     elision disabled so we can test them.  */
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -142,7 +141,6 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
 	      mas);
       return 1;
     }
-#endif
 
   if (pthread_mutex_unlock (m) != 0)
     {
@@ -157,7 +155,6 @@ check_type (const char *mas, pthread_mutexattr_t *ma)
     }
 
   /* Elided mutexes don't fail destroy.  */
-#ifndef ENABLE_LOCK_ELISION
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -171,7 +168,6 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
 	      mas);
       return 1;
     }
-#endif
 
   if (pthread_mutex_unlock (m) != 0)
     {
@@ -207,7 +203,6 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
     }
 
   /* Elided mutexes don't fail destroy.  */
-#ifndef ENABLE_LOCK_ELISION
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -220,7 +215,6 @@ mutex_destroy of self-trylocked mutex did not return EBUSY %s\n",
 mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
       return 1;
     }
-#endif
 
   done = true;
   if (pthread_cond_signal (&c) != 0)
@@ -280,7 +274,6 @@ mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
     }
 
   /* Elided mutexes don't fail destroy.  */
-#ifndef ENABLE_LOCK_ELISION
   e = pthread_mutex_destroy (m);
   if (e == 0)
     {
@@ -295,7 +288,6 @@ mutex_destroy of condvar-used mutex did not return EBUSY for %s\n", mas);
 	      mas);
       return 1;
     }
-#endif
 
   if (pthread_cancel (th) != 0)
     {
diff --git a/scripts/gen-tunables.awk b/scripts/gen-tunables.awk
index 601240a..6dba7e1 100644
--- a/scripts/gen-tunables.awk
+++ b/scripts/gen-tunables.awk
@@ -122,9 +122,9 @@ END {
   }
 
   print "/* AUTOGENERATED by gen-tunables.awk.  */"
-  print "#ifndef _TUNABLES_H_"
+  print "#ifndef _DL_TUNABLES_H_"
   print "# error \"Do not include this file directly.\""
-  print "# error \"Include tunables.h instead.\""
+  print "# error \"Include dl-tunables.h instead.\""
   print "#endif"
 
   # Now, the enum names
diff --git a/sysdeps/powerpc/nptl/elide.h b/sysdeps/powerpc/nptl/elide.h
index 1c42814..06986cc 100644
--- a/sysdeps/powerpc/nptl/elide.h
+++ b/sysdeps/powerpc/nptl/elide.h
@@ -19,7 +19,6 @@
 #ifndef ELIDE_PPC_H
 # define ELIDE_PPC_H
 
-#ifdef ENABLE_LOCK_ELISION
 # include <htm.h>
 # include <elision-conf.h>
 
@@ -114,12 +113,4 @@ __elide_unlock (int is_lock_free)
 # define ELIDE_UNLOCK(is_lock_free) \
   __elide_unlock (is_lock_free)
 
-# else
-
-# define ELIDE_LOCK(adapt_count, is_lock_free) 0
-# define ELIDE_TRYLOCK(adapt_count, is_lock_free, write) 0
-# define ELIDE_UNLOCK(is_lock_free) 0
-
-#endif /* ENABLE_LOCK_ELISION  */
-
 #endif
diff --git a/sysdeps/powerpc/powerpc32/sysdep.h b/sysdeps/powerpc/powerpc32/sysdep.h
index f92ab2c..0ed83d3 100644
--- a/sysdeps/powerpc/powerpc32/sysdep.h
+++ b/sysdeps/powerpc/powerpc32/sysdep.h
@@ -88,7 +88,7 @@ GOT_LABEL:			;					      \
   cfi_endproc;								      \
   ASM_SIZE_DIRECTIVE(name)
 
-#if ! IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+#if ! IS_IN(rtld)
 # define ABORT_TRANSACTION \
     cmpwi    2,0;		\
     beq      1f;		\
diff --git a/sysdeps/powerpc/powerpc64/sysdep.h b/sysdeps/powerpc/powerpc64/sysdep.h
index db7c1d7..79a2697 100644
--- a/sysdeps/powerpc/powerpc64/sysdep.h
+++ b/sysdeps/powerpc/powerpc64/sysdep.h
@@ -272,7 +272,7 @@ LT_LABELSUFFIX(name,_name_end): ; \
   TRACEBACK_MASK(name,mask)	\
   END_2(name)
 
-#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+#if !IS_IN(rtld)
 # define ABORT_TRANSACTION \
     cmpdi    13,0;		\
     beq      1f;		\
diff --git a/sysdeps/powerpc/sysdep.h b/sysdeps/powerpc/sysdep.h
index f07b959..d1a9bd9 100644
--- a/sysdeps/powerpc/sysdep.h
+++ b/sysdeps/powerpc/sysdep.h
@@ -21,10 +21,8 @@
  */
 #define _SYSDEPS_SYSDEP_H 1
 #include <bits/hwcap.h>
-#ifdef ENABLE_LOCK_ELISION
 #include <tls.h>
 #include <htm.h>
-#endif
 
 #define PPC_FEATURE_970 (PPC_FEATURE_POWER4 + PPC_FEATURE_HAS_ALTIVEC)
 
@@ -176,7 +174,7 @@
    we abort transaction just before syscalls.
 
    [1] Documentation/powerpc/transactional_memory.txt [Syscalls]  */
-#if !IS_IN(rtld) && defined (ENABLE_LOCK_ELISION)
+#if !IS_IN(rtld)
 # define ABORT_TRANSACTION \
   ({ 						\
     if (THREAD_GET_TM_CAPABLE ())		\
diff --git a/sysdeps/s390/nptl/bits/pthreadtypes.h b/sysdeps/s390/nptl/bits/pthreadtypes.h
index 48ffdb4..88d21f0 100644
--- a/sysdeps/s390/nptl/bits/pthreadtypes.h
+++ b/sysdeps/s390/nptl/bits/pthreadtypes.h
@@ -89,37 +89,25 @@ typedef union
        binary compatibility with static initializers.  */
     int __kind;
 #if __WORDSIZE == 64
-# ifdef ENABLE_LOCK_ELISION
     short __spins;
     short __elision;
     /* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER.  */
-#  define __PTHREAD_SPINS               0, 0
-# else
-    int __spins;
-    /* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER.  */
-#  define __PTHREAD_SPINS               0
-# endif
+# define __PTHREAD_SPINS               0, 0
     __pthread_list_t __list;
 # define __PTHREAD_MUTEX_HAVE_PREV	1
 #else
     unsigned int __nusers;
     __extension__ union
     {
-# ifdef ENABLE_LOCK_ELISION
       struct
       {
 	short __espins;
 	short __elision;
       } _d;
-#  define __spins _d.__espins
-#  define __elision _d.__elision
-    /* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER.  */
-#  define __PTHREAD_SPINS               { 0, 0 }
-# else
-      int __spins;
-    /* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER.  */
-#  define __PTHREAD_SPINS               0
-# endif
+# define __spins _d.__espins
+# define __elision _d.__elision
+      /* Mutex __spins initializer used by PTHREAD_MUTEX_INITIALIZER.  */
+# define __PTHREAD_SPINS               { 0, 0 }
       __pthread_slist_t __list;
     };
 #endif
diff --git a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c
index f631f0a..a767a0c 100644
--- a/sysdeps/unix/sysv/linux/powerpc/elision-conf.c
+++ b/sysdeps/unix/sysv/linux/powerpc/elision-conf.c
@@ -21,6 +21,7 @@
 #include <elision-conf.h>
 #include <unistd.h>
 #include <dl-procinfo.h>
+#include <elf/dl-tunables.h>
 
 /* Reasonable initial tuning values, may be revised in the future.
    This is a conservative initial value.  */
@@ -54,18 +55,47 @@ int __pthread_force_elision attribute_hidden;
 
 /* Initialize elision.  */
 
+static inline void
+do_set_elision_enable (bool elision_enable)
+{
+  /* If elision is not enabled, or we are in a secure mode,
+     make sure elision is never used...  */
+  if (!elision_enable || __libc_enable_secure)
+    {
+      __pthread_force_elision = 0;
+      return;
+    }
+
+  /* ... otherwise enable elision based on hardare availability.  */
+  __pthread_force_elision = (GLRO (dl_hwcap2)
+			     & PPC_FEATURE2_HAS_HTM) ? 1 : 0;
+}
+
+#if HAVE_TUNABLES
+/* The elision->enable tunable is either 0 or 1 to indicate that
+   elision should be disabled or enabled respectively.  Availability at
+   the hardware level will still dictate if the feature is used.  */
+void
+DL_TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *elision_enable)
+{
+  int32_t elision_enable = (int32_t) valp->numval;
+  do_set_elision_enable (elision_enable ? true : false);
+}
+#endif
+
 static void
 elision_init (int argc __attribute__ ((unused)),
 	      char **argv  __attribute__ ((unused)),
 	      char **environ)
 {
-#ifdef ENABLE_LOCK_ELISION
-  int elision_available = (GLRO (dl_hwcap2) & PPC_FEATURE2_HAS_HTM) ? 1 : 0;
-  __pthread_force_elision = __libc_enable_secure ? 0 : elision_available;
+#if HAVE_TUNABLES
+  /* Elision depends on tunables to enable and tune elision at runtime.  */
+# define TUNABLE_NAMESPACE elision
+  TUNABLE_SET_VAL_WITH_CALLBACK (enable, NULL, set_elision_enable);
+#else
+  /* Disable elision when built without tunables.  */
+  do_set_elision_enable (false);
 #endif
-  if (!__pthread_force_elision)
-    /* Disable elision on rwlocks.  */
-    __elision_aconf.try_tbegin = 0;
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/powerpc/force-elision.h b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
index 318f791..d1feeeb 100644
--- a/sysdeps/unix/sysv/linux/powerpc/force-elision.h
+++ b/sysdeps/unix/sysv/linux/powerpc/force-elision.h
@@ -16,7 +16,6 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifdef ENABLE_LOCK_ELISION
 /* Automatically enable elision for existing user lock kinds.  */
 #define FORCE_ELISION(m, s)						\
   if (__pthread_force_elision						\
@@ -25,4 +24,3 @@
       mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP;			\
       s;								\
     }
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.c b/sysdeps/unix/sysv/linux/s390/elision-conf.c
index cc0fdef..c6d9962 100644
--- a/sysdeps/unix/sysv/linux/s390/elision-conf.c
+++ b/sysdeps/unix/sysv/linux/s390/elision-conf.c
@@ -21,6 +21,7 @@
 #include <elision-conf.h>
 #include <unistd.h>
 #include <dl-procinfo.h>
+#include <elf/dl-tunables.h>
 
 /* Reasonable initial tuning values, may be revised in the future.
    This is a conservative initial value.  */
@@ -55,16 +56,46 @@ int __pthread_force_elision attribute_hidden = 0;
 
 /* Initialize elison.  */
 
+static inline void
+do_set_elision_enable (bool elision_enable)
+{
+  /* If elision is not enabled, or we are in a secure mode,
+     make sure elision is never used...  */
+  if (!elision_enable || __libc_enable_secure)
+    {
+      __pthread_force_elision = 0;
+      return;
+    }
+
+  /* ... otherwise enable elision based on hardare availability.  */
+  __pthread_force_elision = (GLRO (dl_hwcap) & HWCAP_S390_TE) ? 1 : 0;
+}
+
+#if HAVE_TUNABLES
+/* The elision->enable tunable is either 0 or 1 to indicate that
+   elision should be disabled or enabled respectively.  Availability at
+   the hardware level will still dictate if the feature is used.  */
+void
+DL_TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *elision_enable)
+{
+  int32_t elision_enable = (int32_t) valp->numval;
+  do_set_elision_enable (elision_enable ? true : false);
+}
+#endif
+
 static void
 elision_init (int argc __attribute__ ((unused)),
 	      char **argv  __attribute__ ((unused)),
 	      char **environ)
 {
-  /* Set when the CPU and the kernel supports transactional execution.
-     When false elision is never attempted.  */
-  int elision_available = (GLRO (dl_hwcap) & HWCAP_S390_TE) ? 1 : 0;
-
-  __pthread_force_elision = __libc_enable_secure ? 0 : elision_available;
+#if HAVE_TUNABLES
+  /* Elision depends on tunables to enable and tune elision at runtime.  */
+# define TUNABLE_NAMESPACE elision
+  TUNABLE_SET_VAL_WITH_CALLBACK (enable, NULL, set_elision_enable);
+#else
+  /* Disable elision when built without tunables.  */
+  do_set_elision_enable (false);
+#endif
 }
 
 #ifdef SHARED
diff --git a/sysdeps/unix/sysv/linux/s390/elision-conf.h b/sysdeps/unix/sysv/linux/s390/elision-conf.h
index 3143f3b..32f0ed3 100644
--- a/sysdeps/unix/sysv/linux/s390/elision-conf.h
+++ b/sysdeps/unix/sysv/linux/s390/elision-conf.h
@@ -15,7 +15,6 @@
    You should have received a copy of the GNU Lesser General Public
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
-#ifdef ENABLE_LOCK_ELISION
 #ifndef _ELISION_CONF_H
 #define _ELISION_CONF_H 1
 
@@ -41,4 +40,3 @@ extern int __pthread_force_elision attribute_hidden;
 #define HAVE_ELISION 1
 
 #endif
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/force-elision.h b/sysdeps/unix/sysv/linux/s390/force-elision.h
index 3ae3bcd..8e1e33e 100644
--- a/sysdeps/unix/sysv/linux/s390/force-elision.h
+++ b/sysdeps/unix/sysv/linux/s390/force-elision.h
@@ -16,7 +16,6 @@
    License along with the GNU C Library; if not, see
    <http://www.gnu.org/licenses/>.  */
 
-#ifdef ENABLE_LOCK_ELISION
 /* Automatically enable elision for existing user lock kinds.  */
 #define FORCE_ELISION(m, s)						\
   if (__pthread_force_elision						\
@@ -25,4 +24,3 @@
       mutex->__data.__kind |= PTHREAD_MUTEX_ELISION_NP;			\
       s;								\
     }
-#endif
diff --git a/sysdeps/unix/sysv/linux/s390/lowlevellock.h b/sysdeps/unix/sysv/linux/s390/lowlevellock.h
index 604137f..48f87a8 100644
--- a/sysdeps/unix/sysv/linux/s390/lowlevellock.h
+++ b/sysdeps/unix/sysv/linux/s390/lowlevellock.h
@@ -22,7 +22,6 @@
 #include <sysdeps/nptl/lowlevellock.h>
 
 /* Transactional lock elision definitions.  */
-# ifdef ENABLE_LOCK_ELISION
 extern int __lll_timedlock_elision
   (int *futex, short *adapt_count, const struct timespec *timeout, int private)
   attribute_hidden;
@@ -45,6 +44,5 @@ extern int __lll_trylock_elision(int *futex, short *adapt_count)
   __lll_unlock_elision (&(futex), &(adapt_count), private)
 #  define lll_trylock_elision(futex, adapt_count) \
   __lll_trylock_elision(&(futex), &(adapt_count))
-# endif  /* ENABLE_LOCK_ELISION */
 
 #endif	/* lowlevellock.h */
diff --git a/sysdeps/unix/sysv/linux/x86/elision-conf.c b/sysdeps/unix/sysv/linux/x86/elision-conf.c
index 673b000..7d3d8fd 100644
--- a/sysdeps/unix/sysv/linux/x86/elision-conf.c
+++ b/sysdeps/unix/sysv/linux/x86/elision-conf.c
@@ -21,6 +21,7 @@
 #include <init-arch.h>
 #include <elision-conf.h>
 #include <unistd.h>
+#include <elf/dl-tunables.h>
 
 /* Reasonable initial tuning values, may be revised in the future.
    This is a conservative initial value.  */
@@ -52,17 +53,46 @@ int __pthread_force_elision attribute_hidden;
 
 /* Initialize elison.  */
 
+static inline void
+do_set_elision_enable (bool elision_enable)
+{
+  /* If elision is not enabled, or we are in a secure mode,
+     make sure elision is never used...  */
+  if (!elision_enable || __libc_enable_secure)
+    {
+      __pthread_force_elision = 0;
+      return;
+    }
+
+  /* ... otherwise enable elision based on hardare availability.  */
+  __pthread_force_elision = HAS_CPU_FEATURE (RTM);
+}
+
+#if HAVE_TUNABLES
+/* The elision->enable tunable is either 0 or 1 to indicate that
+   elision should be disabled or enabled respectively.  Availability at
+   the hardware level will still dictate if the feature is used.  */
+void
+DL_TUNABLE_CALLBACK (set_elision_enable) (tunable_val_t *valp)
+{
+  int32_t elision_enable = (int32_t) valp->numval;
+  do_set_elision_enable (elision_enable ? true : false);
+}
+#endif
+
 static void
 elision_init (int argc __attribute__ ((unused)),
 	      char **argv  __attribute__ ((unused)),
 	      char **environ)
 {
-  int elision_available = HAS_CPU_FEATURE (RTM);
-#ifdef ENABLE_LOCK_ELISION
-  __pthread_force_elision = __libc_enable_secure ? 0 : elision_available;
+#if HAVE_TUNABLES
+  /* Elision depends on tunables to enable and tune elision at runtime.  */
+# define TUNABLE_NAMESPACE elision
+  TUNABLE_SET_VAL_WITH_CALLBACK (enable, NULL, set_elision_enable);
+#else
+  /* Disable elision when built without tunables.  */
+  do_set_elision_enable (false);
 #endif
-  if (!elision_available)
-    __elision_aconf.retry_try_xbegin = 0; /* Disable elision on rwlocks */
 }
 
 #ifdef SHARED
