]> git.ipfire.org Git - thirdparty/glibc.git/commitdiff
Updated to fedora-glibc-20061109T1949
authorJakub Jelinek <jakub@redhat.com>
Thu, 9 Nov 2006 19:57:49 +0000 (19:57 +0000)
committerJakub Jelinek <jakub@redhat.com>
Thu, 9 Nov 2006 19:57:49 +0000 (19:57 +0000)
12 files changed:
ChangeLog
elf/dl-debug.c
elf/dl-load.c
fedora/branch.mk
fedora/glibc.spec.in
include/libc-symbols.h
sysdeps/gnu/errlist-compat.awk
sysdeps/gnu/siglist.c
sysdeps/powerpc/fpu/bits/mathinline.h
sysdeps/powerpc/fpu/math_private.h [new file with mode: 0644]
sysdeps/unix/sysv/linux/i386/sysconf.c
sysdeps/unix/sysv/linux/x86_64/sysconf.c

index 876c91d494a4197280271841122ac6433ac28890..9aef65289dae86b3c7e2047402fca594e0fff415 100644 (file)
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,7 +1,42 @@
+2006-10-09  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-debug.c (_dl_debug_initialize): Check r->r_map for 0
+       rather than r->r_brk.
+
+2006-11-08  Jakub Jelinek  <jakub@redhat.com>
+
+       * elf/dl-load.c (decompose_rpath): Return bool rather than void.
+       If l->l_name is on inhibit_rpath list, set sps->dirs to -1 and
+       return false, otherwise return true.
+       (cache_rpath): Return decompose_rpath return value.
+
+2006-11-07  Jakub Jelinek  <jakub@redhat.com>
+
+       * include/libc-symbols.h (declare_symbol): Rename to...
+       (declare_symbol_alias): ... this.  Add ORIGINAL argument, imply
+       strong_alias (ORIGINAL, SYMBOL) in asm to make sure it preceedes
+       .size directive.
+       * sysdeps/gnu/errlist-compat.awk: Adjust for declare_symbol_alias
+       changes.
+       * sysdeps/gnu/siglist.c: Likewise.
+
+2006-11-03  Steven Munroe  <sjmunroe@us.ibm.com>
+
+       * sysdeps/powerpc/fpu/bits/mathinline.h
+       [__LIBC_INTERNAL_MATH_INLINES]: Moved to ...
+       * sysdeps/powerpc/fpu/math_private.h: ...here.  New file.
+
+2006-11-05  Ulrich Drepper  <drepper@redhat.com>
+
+       * sysdeps/unix/sysv/linux/i386/sysconf.c (intel_check_word):
+       Update handling of cache descriptor 0x49 for new models.
+       * sysdeps/unix/sysv/linux/x86_64/sysconf.c (intel_check_word):
+       Likewise.
+
 2006-11-02  Jakub Jelinek  <jakub@redhat.com>
 
-       * malloc/memusage.c (dest): Reset not_me back to false after printing
-       statistics.
+       * malloc/memusage.c (dest): Reset not_me back to false after
+       printing statistics.
 
 2006-11-02  Ulrich Drepper  <drepper@redhat.com>
 
index d00fe87fbbfb006c9f573c0a1d963fdb04092872..2538364aec8f0f3d19684744708b19f6ba2350e1 100644 (file)
@@ -54,7 +54,7 @@ _dl_debug_initialize (ElfW(Addr) ldbase, Lmid_t ns)
   else
     r = &GL(dl_ns)[ns]._ns_debug;
 
-  if (r->r_brk == 0 || ldbase != 0)
+  if (r->r_map == NULL || ldbase != 0)
     {
       /* Tell the debugger where to find the map of loaded objects.  */
       r->r_version = 1 /* R_DEBUG_VERSION XXX */;
index ccbbf4fdd2fc036f9c4dfa087bedb0f982be4b21..1650ef953a7a04712b14af7c9c7e7eaf77187cc3 100644 (file)
@@ -511,7 +511,7 @@ fillin_rpath (char *rpath, struct r_search_path_elem **result, const char *sep,
 }
 
 
-static void
+static bool
 internal_function
 decompose_rpath (struct r_search_path_struct *sps,
                 const char *rpath, struct link_map *l, const char *what)
@@ -546,19 +546,8 @@ decompose_rpath (struct r_search_path_struct *sps,
            {
              /* This object is on the list of objects for which the
                 RUNPATH and RPATH must not be used.  */
-             result = calloc (1, sizeof *result);
-             if (result == NULL)
-               {
-               signal_error_cache:
-                 errstring = N_("cannot create cache for search path");
-               signal_error:
-                 _dl_signal_error (ENOMEM, NULL, NULL, errstring);
-               }
-
-             sps->dirs = result;
-             sps->malloced = 1;
-
-             return;
+             sps->dirs = (void *) -1;
+             return false;
            }
 
          while (*inhp != '\0')
@@ -588,7 +577,11 @@ decompose_rpath (struct r_search_path_struct *sps,
   result = (struct r_search_path_elem **) malloc ((nelems + 1 + 1)
                                                  * sizeof (*result));
   if (result == NULL)
-    goto signal_error_cache;
+    {
+      errstring = N_("cannot create cache for search path");
+    signal_error:
+      _dl_signal_error (ENOMEM, NULL, NULL, errstring);
+    }
 
   fillin_rpath (copy, result, ":", 0, what, where);
 
@@ -599,6 +592,7 @@ decompose_rpath (struct r_search_path_struct *sps,
   sps->dirs = result;
   /* The caller will change this value if we haven't used a real malloc.  */
   sps->malloced = 1;
+  return true;
 }
 
 /* Make sure cached path information is stored in *SP
@@ -623,10 +617,9 @@ cache_rpath (struct link_map *l,
     }
 
   /* Make sure the cache information is available.  */
-  decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
-                                      + l->l_info[tag]->d_un.d_val),
-                  l, what);
-  return true;
+  return decompose_rpath (sp, (const char *) (D_PTR (l, l_info[DT_STRTAB])
+                                             + l->l_info[tag]->d_un.d_val),
+                         l, what);
 }
 
 
index 040e9efd2dcca2c313026d22f9190ed6ffdd86b6..01c3d482b7d4250a553aaebd558b80e88a296184 100644 (file)
@@ -3,5 +3,5 @@ glibc-branch := fedora
 glibc-base := HEAD
 DIST_BRANCH := devel
 COLLECTION := dist-fc4
-fedora-sync-date := 2006-11-03 16:10 UTC
-fedora-sync-tag := fedora-glibc-20061103T1610
+fedora-sync-date := 2006-11-09 19:49 UTC
+fedora-sync-tag := fedora-glibc-20061109T1949
index 4b1b31cb9e396e76ba98876a0ade9c598558ebc0..b457584cc35fd5bb15b07aee74c4d4d1a7115d11 100644 (file)
@@ -1,4 +1,4 @@
-%define glibcrelease 4
+%define glibcrelease 5
 %define auxarches i586 i686 athlon sparcv9 alphaev6
 %define xenarches i686 athlon
 %ifarch %{xenarches}
@@ -1529,6 +1529,15 @@ rm -f *.filelist*
 %endif
 
 %changelog
+* Thu Nov  9 2006 Jakub Jelinek <jakub@redhat.com> 2.5.90-5
+- fix sysconf (_SC_LEVEL{2,3}_CACHE_SIZE) on Intel Core Duo
+  CPUs
+- fix libthread_db.so on TLS_DTV_AT_TP architectures
+- fix --inhibit-rpath (#214569)
+- fix _r_debug content when prelinked ld.so executes
+  a program as its argument
+- powerpc-cpu add-on updates
+
 * Fri Nov  3 2006 Jakub Jelinek <jakub@redhat.com> 2.5.90-4
 - fix atexit backwards compatibility (#213388)
 - add mai_IN locale (#213415)
index 9eabcbd3548679b710d2d1757a8ffeda9ba2d35c..a2faeafb32a707d075dedc5d7a858ed5e3da4da6 100644 (file)
@@ -294,27 +294,42 @@ requires at runtime the shared libraries from the glibc version used \
 for linking")
 #endif
 
-/* Declare SYMBOL to be TYPE (`function' or `object') and of SIZE bytes,
-   when the assembler supports such declarations (such as in ELF).
+/* Declare SYMBOL to be TYPE (`function' or `object') of SIZE bytes
+   alias to ORIGINAL, when the assembler supports such declarations
+   (such as in ELF).
    This is only necessary when defining something in assembly, or playing
    funny alias games where the size should be other than what the compiler
    thinks it is.  */
-#define declare_symbol(symbol, type, size) \
-  declare_symbol_1 (symbol, type, size)
+#define declare_symbol_alias(symbol, original, type, size) \
+  declare_symbol_alias_1 (symbol, original, type, size)
 #ifdef ASM_TYPE_DIRECTIVE_PREFIX
 # ifdef __ASSEMBLER__
-#  define declare_symbol_1(symbol, type, size) \
+#  define declare_symbol_alias_1(symbol, original, type, size) \
+    strong_alias (original, symbol); \
     .type C_SYMBOL_NAME (symbol), \
-         declare_symbol_1_paste (ASM_TYPE_DIRECTIVE_PREFIX, type), size
-#  define declare_symbol_1_paste(a, b) declare_symbol_1_paste_1 (a,b)
-#  define declare_symbol_1_paste_1(a,b)        a##b
+         declare_symbol_alias_1_paste (ASM_TYPE_DIRECTIVE_PREFIX, type); \
+    .size C_SYMBOL_NAME (symbol), size
+#  define declare_symbol_alias_1_paste(a, b) \
+  declare_symbol_alias_1_paste_1 (a,b)
+#  define declare_symbol_alias_1_paste_1(a,b)  a##b
 # else /* Not __ASSEMBLER__.  */
-#  define declare_symbol_1(symbol, type, size) \
-    asm (".type " __SYMBOL_PREFIX #symbol ", " \
-        declare_symbol_1_stringify (ASM_TYPE_DIRECTIVE_PREFIX) #type \
+#  define declare_symbol_alias_1(symbol, original, type, size) \
+    asm (declare_symbol_alias_1_stringify (ASM_GLOBAL_DIRECTIVE) \
+        " " __SYMBOL_PREFIX #symbol \
+        "\n\t" declare_symbol_alias_1_alias (symbol, original) \
+        "\n\t.type " __SYMBOL_PREFIX #symbol ", " \
+        declare_symbol_alias_1_stringify (ASM_TYPE_DIRECTIVE_PREFIX) #type \
         "\n\t.size " __SYMBOL_PREFIX #symbol ", " #size);
-#  define declare_symbol_1_stringify(x) declare_symbol_1_stringify_1 (x)
-#  define declare_symbol_1_stringify_1(x) #x
+#  define declare_symbol_alias_1_stringify(x) \
+  declare_symbol_alias_1_stringify_1 (x)
+#  define declare_symbol_alias_1_stringify_1(x) #x
+#  ifdef HAVE_ASM_SET_DIRECTIVE
+#   define declare_symbol_alias_1_alias(symbol, original) \
+        ".set " __SYMBOL_PREFIX #symbol ", " __SYMBOL_PREFIX #original
+#  else
+#   define declare_symbol_alias_1_alias(symbol, original) \
+        __SYMBOL_PREFIX #symbol " = " __SYMBOL_PREFIX #original
+#  endif /* HAVE_ASM_SET_DIRECTIVE */
 # endif /* __ASSEMBLER__ */
 #else
 # define declare_symbol_1(symbol, type, size) /* Nothing.  */
index ab67a18f64ad899721d4bd1b4731d004985e0909..307c4d702098485103c35e5e5080a6076bc2a388 100644 (file)
@@ -1,5 +1,5 @@
 # awk script to generate errlist-compat.c
-# Copyright (C) 2002, 2004 Free Software Foundation, Inc.
+# Copyright (C) 2002, 2004, 2006 Free Software Foundation, Inc.
 # This file is part of the GNU C Library.
 
 # The GNU C Library is free software; you can redistribute it and/or
@@ -92,16 +92,18 @@ END {
     printf "# include <bits/wordsize.h>\n";
     printf "extern const char *const __sys_errlist_%s[NERR];\n", old;
     printf "const int __sys_nerr_%s = %d;\n", old, n;
-    printf "strong_alias (_sys_errlist_internal, __sys_errlist_%s)\n", old;
-    printf "declare_symbol (__sys_errlist_%s, object, __WORDSIZE/8*%d)\n", \
-      old, n;
+    printf "declare_symbol_alias (__sys_errlist_%s, _sys_errlist_internal,", \
+      old;
+    printf " object, __WORDSIZE/8*%d)\n", n;
     printf "compat_symbol (libc, __sys_errlist_%s, sys_errlist, %s);\n", \
       old, old;
     printf "compat_symbol (libc, __sys_nerr_%s, sys_nerr, %s);\n", old, old;
 
     printf "extern const char *const ___sys_errlist_%s[NERR];\n", old;
     printf "extern const int __sys_nerr_%s;\n", old;
-    printf "strong_alias (__sys_errlist_%s, ___sys_errlist_%s)\n", old, old;
+    printf "declare_symbol_alias (___sys_errlist_%s, _sys_errlist_internal,", \
+      old;
+    printf " object, __WORDSIZE/8*%d)\n", n;
     printf "strong_alias (__sys_nerr_%s, ___sys_nerr_%s)\n", old, old;
     printf "compat_symbol (libc, ___sys_errlist_%s, _sys_errlist, %s);\n", \
       old, old;
index cb1875f9eba88c46566ec651709173526c8a10a6..b8d37968e09305c3ac689e74b837d777a610d946 100644 (file)
@@ -1,5 +1,5 @@
 /* Define list of all signal numbers and their names.
-   Copyright (C) 1997-2000, 2002, 2003 Free Software Foundation, Inc.
+   Copyright (C) 1997-2000, 2002, 2003, 2006 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
 
    The GNU C Library is free software; you can redistribute it and/or
@@ -40,11 +40,11 @@ const char *const __new_sys_sigabbrev[NSIG] =
 strong_alias (__new_sys_sigabbrev, _sys_sigabbrev_internal)
 
 #if SHLIB_COMPAT (libc, GLIBC_2_0, GLIBC_2_1)
-strong_alias (_sys_siglist_internal, __old_sys_siglist)
-declare_symbol (__old_sys_siglist, object, OLD_SIGLIST_SIZE * __WORDSIZE / 8)
+declare_symbol_alias (__old_sys_siglist, _sys_siglist_internal, object,
+                     OLD_SIGLIST_SIZE * __WORDSIZE / 8)
 
-strong_alias (_sys_sigabbrev_internal, __old_sys_sigabbrev)
-declare_symbol (__old_sys_sigabbrev, object, OLD_SIGLIST_SIZE * __WORDSIZE / 8)
+declare_symbol_alias (__old_sys_sigabbrev, _sys_sigabbrev_internal, object,
+                     OLD_SIGLIST_SIZE * __WORDSIZE / 8)
 
 strong_alias (__old_sys_siglist, _old_sys_siglist)
 compat_symbol (libc, __old_sys_siglist, _sys_siglist, GLIBC_2_0);
@@ -53,14 +53,15 @@ compat_symbol (libc, __old_sys_sigabbrev, sys_sigabbrev, GLIBC_2_0);
 #endif
 
 #if SHLIB_COMPAT (libc, GLIBC_2_1, GLIBC_2_3_3) && defined OLD2_SIGLIST_SIZE
-strong_alias (_sys_siglist_internal, __old2_sys_siglist)
-declare_symbol (__old2_sys_siglist, object, OLD2_SIGLIST_SIZE * __WORDSIZE / 8)
+declare_symbol_alias (__old2_sys_siglist, __new_sys_siglist, object,
+                     OLD2_SIGLIST_SIZE * __WORDSIZE / 8)
 
-strong_alias (_sys_sigabbrev_internal, __old2_sys_sigabbrev)
-declare_symbol (__old2_sys_sigabbrev, object,
-               OLD2_SIGLIST_SIZE * __WORDSIZE / 8)
+declare_symbol_alias (__old2_sys_sigabbrev, __new_sys_sigabbrev, object,
+                     OLD2_SIGLIST_SIZE * __WORDSIZE / 8)
+
+declare_symbol_alias (_old2_sys_siglist, __new_sys_siglist, object,
+                     OLD2_SIGLIST_SIZE * __WORDSIZE / 8)
 
-strong_alias (__old2_sys_siglist, _old2_sys_siglist)
 compat_symbol (libc, __old2_sys_siglist, _sys_siglist, GLIBC_2_1);
 compat_symbol (libc, _old2_sys_siglist, sys_siglist, GLIBC_2_1);
 compat_symbol (libc, __old2_sys_sigabbrev, sys_sigabbrev, GLIBC_2_1);
index aed899e8824cc7afe9587e83878524295d180071..04478309d9f993344050538217d0ac7b0dde8235 100644 (file)
@@ -121,62 +121,4 @@ __NTH (fdimf (float __x, float __y))
 
 #endif /* __USE_ISOC99 */
 #endif /* !__NO_MATH_INLINES && __OPTIMIZE__ */
-
-/* This code is used internally in the GNU libc.  */
-#ifdef __LIBC_INTERNAL_MATH_INLINES
-
-#include <sysdep.h>
-#include <ldsodefs.h>
-#include <dl-procinfo.h>
-
-# if __WORDSIZE == 64 || defined _ARCH_PWR4
-#  define __CPU_HAS_FSQRT 1
-# else
-#  define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
-# endif
-
-extern double __slow_ieee754_sqrt (double);
-__MATH_INLINE double
-__NTH (__ieee754_sqrt (double __x))
-{
-  double __z;
-
-  /* If the CPU is 64-bit we can use the optional FP instructions.  */
-  if (__CPU_HAS_FSQRT)
-  {
-    /* Volatile is required to prevent the compiler from moving the
-       fsqrt instruction above the branch.  */
-     __asm __volatile (
-       "       fsqrt   %0,%1\n"
-               : "=f" (__z)
-               : "f" (__x));
-  }
-  else
-     __z = __slow_ieee754_sqrt(__x);
-
-  return __z;
-}
-
-extern float __slow_ieee754_sqrtf (float);
-__MATH_INLINE float
-__NTH (__ieee754_sqrtf (float __x))
-{
-  float __z;
-
-  /* If the CPU is 64-bit we can use the optional FP instructions.  */
-  if (__CPU_HAS_FSQRT)
-  {
-    /* Volatile is required to prevent the compiler from moving the
-       fsqrts instruction above the branch.  */
-     __asm __volatile (
-       "       fsqrts  %0,%1\n"
-               : "=f" (__z)
-               : "f" (__x));
-  }
-  else
-     __z = __slow_ieee754_sqrtf(__x);
-
-  return __z;
-}
-#endif /* __LIBC_INTERNAL_MATH_INLINES */
 #endif /* __GNUC__ && !_SOFT_FLOAT */
diff --git a/sysdeps/powerpc/fpu/math_private.h b/sysdeps/powerpc/fpu/math_private.h
new file mode 100644 (file)
index 0000000..90021c6
--- /dev/null
@@ -0,0 +1,83 @@
+/* Private inline math functions for powerpc.
+   Copyright (C) 2006
+   Free Software Foundation, Inc.
+   This file is part of the GNU C Library.
+
+   The GNU C Library is free software; you can redistribute it and/or
+   modify it under the terms of the GNU Lesser General Public
+   License as published by the Free Software Foundation; either
+   version 2.1 of the License, or (at your option) any later version.
+
+   The GNU C Library is distributed in the hope that it will be useful,
+   but WITHOUT ANY WARRANTY; without even the implied warranty of
+   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
+   Lesser General Public License for more details.
+
+   You should have received a copy of the GNU Lesser General Public
+   License along with the GNU C Library; if not, write to the Free
+   Software Foundation, Inc., 51 Franklin St - Fifth Floor, Boston,
+   MA 02110-1301 USA  */
+
+#ifndef _PPC_MATH_PRIVATE_H_
+#define _PPC_MATH_PRIVATE_H_
+
+#include <sysdep.h>
+#include <ldsodefs.h>
+#include <dl-procinfo.h>
+
+# if __WORDSIZE == 64 || defined _ARCH_PWR4
+#  define __CPU_HAS_FSQRT 1
+# else
+#  define __CPU_HAS_FSQRT ((GLRO(dl_hwcap) & PPC_FEATURE_64) != 0)
+# endif
+
+# ifndef __LIBC_INTERNAL_MATH_INLINES
+extern double __slow_ieee754_sqrt (double);
+__inline double
+__ieee754_sqrt (double __x)
+{
+  double __z;
+
+  /* If the CPU is 64-bit we can use the optional FP instructions.  */
+  if (__CPU_HAS_FSQRT)
+  {
+    /* Volatile is required to prevent the compiler from moving the
+       fsqrt instruction above the branch.  */
+     __asm __volatile (
+       "       fsqrt   %0,%1\n"
+               : "=f" (__z)
+               : "f" (__x));
+  }
+  else
+     __z = __slow_ieee754_sqrt(__x);
+
+  return __z;
+}
+
+extern float __slow_ieee754_sqrtf (float);
+
+__inline float
+__ieee754_sqrtf (float __x)
+{
+  float __z;
+
+  /* If the CPU is 64-bit we can use the optional FP instructions.  */
+  if (__CPU_HAS_FSQRT)
+  {
+    /* Volatile is required to prevent the compiler from moving the
+       fsqrts instruction above the branch.  */
+     __asm __volatile (
+       "       fsqrts  %0,%1\n"
+               : "=f" (__z)
+               : "f" (__x));
+  }
+  else
+     __z = __slow_ieee754_sqrtf(__x);
+
+  return __z;
+}
+#endif /* __LIBC_INTERNAL_MATH_INLINES */
+
+#include <math/math_private.h>
+
+#endif /* _PPC_MATH_PRIVATE_H_ */
index 25b9ba734e27852241b62f28235ae7305280f6f6..c9d7f77a0001998f78e75396c7992bda989b47d2 100644 (file)
@@ -97,7 +97,7 @@ static const struct intel_02_cache_info
     { 0x45, _SC_LEVEL2_CACHE_SIZE, 2097152, 4, 32 },
     { 0x46, _SC_LEVEL3_CACHE_SIZE, 4194304, 4, 64 },
     { 0x47, _SC_LEVEL3_CACHE_SIZE, 8388608, 8, 64 },
-    { 0x49, _SC_LEVEL3_CACHE_SIZE, 4194304, 16, 64 },
+    { 0x49, _SC_LEVEL2_CACHE_SIZE, 4194304, 16, 64 },
     { 0x4a, _SC_LEVEL3_CACHE_SIZE, 6291456, 12, 64 },
     { 0x4b, _SC_LEVEL3_CACHE_SIZE, 8388608, 16, 64 },
     { 0x4c, _SC_LEVEL3_CACHE_SIZE, 12582912, 12, 64 },
@@ -166,6 +166,33 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
        }
       else
        {
+         if (byte == 0x49 && folded_name == _SC_LEVEL3_CACHE_SIZE)
+           {
+             /* Intel reused this value.  For family 15, model 6 it
+                specifies the 3rd level cache.  Otherwise the 2nd
+                level cache.  */
+             unsigned int eax;
+             unsigned int ebx;
+             unsigned int ecx;
+             unsigned int edx;
+             asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+                           : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+                           : "0" (1));
+
+             unsigned int family = ((eax >> 20) & 0xff) + ((eax >> 8) & 0xf);
+             unsigned int model = ((((eax >>16) & 0xf) << 4)
+                                   + ((eax >> 4) & 0xf));
+             if (family == 15 && model == 6)
+               {
+                 /* The level 3 cache is encoded for this model like
+                    the level 2 cache is for other models.  Pretend
+                    the caller asked for the level 2 cache.  */
+                 name = (_SC_LEVEL2_CACHE_SIZE
+                         + (name - _SC_LEVEL3_CACHE_SIZE));
+                 folded_name = _SC_LEVEL3_CACHE_SIZE;
+               }
+           }
+
          struct intel_02_cache_info *found;
          struct intel_02_cache_info search;
 
index 726c5e33acedf1698be5bdee669c5df09578dedd..80c982aa3be99da332b7ee3f29c0206abdf6c341 100644 (file)
@@ -58,7 +58,7 @@ static const struct intel_02_cache_info
     { 0x45, _SC_LEVEL2_CACHE_SIZE, 2097152, 4, 32 },
     { 0x46, _SC_LEVEL3_CACHE_SIZE, 4194304, 4, 64 },
     { 0x47, _SC_LEVEL3_CACHE_SIZE, 8388608, 8, 64 },
-    { 0x49, _SC_LEVEL3_CACHE_SIZE, 4194304, 16, 64 },
+    { 0x49, _SC_LEVEL2_CACHE_SIZE, 4194304, 16, 64 },
     { 0x4a, _SC_LEVEL3_CACHE_SIZE, 6291456, 12, 64 },
     { 0x4b, _SC_LEVEL3_CACHE_SIZE, 8388608, 16, 64 },
     { 0x4c, _SC_LEVEL3_CACHE_SIZE, 12582912, 12, 64 },
@@ -127,6 +127,33 @@ intel_check_word (int name, unsigned int value, bool *has_level_2,
        }
       else
        {
+         if (byte == 0x49 && folded_name == _SC_LEVEL3_CACHE_SIZE)
+           {
+             /* Intel reused this value.  For family 15, model 6 it
+                specifies the 3rd level cache.  Otherwise the 2nd
+                level cache.  */
+             unsigned int eax;
+             unsigned int ebx;
+             unsigned int ecx;
+             unsigned int edx;
+             asm volatile ("xchgl %%ebx, %1; cpuid; xchgl %%ebx, %1"
+                           : "=a" (eax), "=r" (ebx), "=c" (ecx), "=d" (edx)
+                           : "0" (1));
+
+             unsigned int family = ((eax >> 20) & 0xff) + ((eax >> 8) & 0xf);
+             unsigned int model = ((((eax >>16) & 0xf) << 4)
+                                   + ((eax >> 4) & 0xf));
+             if (family == 15 && model == 6)
+               {
+                 /* The level 3 cache is encoded for this model like
+                    the level 2 cache is for other models.  Pretend
+                    the caller asked for the level 2 cache.  */
+                 name = (_SC_LEVEL2_CACHE_SIZE
+                         + (name - _SC_LEVEL3_CACHE_SIZE));
+                 folded_name = _SC_LEVEL3_CACHE_SIZE;
+               }
+           }
+
          struct intel_02_cache_info *found;
          struct intel_02_cache_info search;