diff --git a/sysdeps/x86/cacheinfo.c b/sysdeps/x86/cacheinfo.c
index 02c886c..4b26fe1 100644
--- a/sysdeps/x86/cacheinfo.c
+++ b/sysdeps/x86/cacheinfo.c
@@ -435,6 +435,55 @@ handle_amd (int name)
   return -1;
 }

+static long int __attribute__ ((noinline))
+handle_zhaoxin (int name)
+{
+  unsigned int eax;
+  unsigned int ebx;
+  unsigned int ecx;
+  unsigned int edx;
+
+  int folded_rel_name = (M(name) / 3) * 3;
+
+  unsigned int round = 0;
+  while (1)
+       {
+         __cpuid_count (4, round, eax, ebx, ecx, edx);
+
+         enum { null = 0, data = 1, inst = 2, uni = 3 } type = eax & 0x1f;
+         if (type == null)
+               break;
+
+         unsigned int level = (eax >> 5) & 0x7;
+
+         if ((level == 1 && type == data
+               && folded_rel_name == M(_SC_LEVEL1_DCACHE_SIZE))
+               || (level == 1 && type == inst
+                   && folded_rel_name == M(_SC_LEVEL1_ICACHE_SIZE))
+               || (level == 2 && folded_rel_name == M(_SC_LEVEL2_CACHE_SIZE))
+               || (level == 3 && folded_rel_name == M(_SC_LEVEL3_CACHE_SIZE)))
+           {
+                 unsigned int offset = M(name) - folded_rel_name;
+
+                 if (offset == 0)
+                   /* Cache size.  */
+                   return (((ebx >> 22) + 1)
+                           * (((ebx >> 12) & 0x3ff) + 1)
+                           * ((ebx & 0xfff) + 1)
+                           * (ecx + 1));
+                 if (offset == 1)
+                   return (ebx >> 22) + 1;
+
+                 assert (offset == 2);
+                 return (ebx & 0xfff) + 1;
+           }
+
+         ++round;
+       }
+
+  /* Nothing found.  */
+  return 0;
+}

 /* Get the value of the system variable NAME.  */
 long int
@@ -449,6 +498,9 @@ __cache_sysconf (int name)
   if (cpu_features->basic.kind == arch_kind_amd)
     return handle_amd (name);

+  if (cpu_features->basic.kind == arch_kind_zhaoxin)
+    return handle_zhaoxin (name);
+
   // XXX Fill in more vendors.

   /* CPU not known, we have no information.  */
@@ -751,6 +803,137 @@ intel_bug_no_cache_info:
        }
 #endif
     }
+  else if (cpu_features->basic.kind == arch_kind_zhaoxin)
+    {
+      data   = handle_zhaoxin (_SC_LEVEL1_DCACHE_SIZE);
+      long int core = handle_zhaoxin (_SC_LEVEL2_CACHE_SIZE);
+      shared = handle_zhaoxin (_SC_LEVEL3_CACHE_SIZE);
+
+         /* Number of logical processors sharing L2 cache.  */
+         int threads_l2;
+
+         /* Number of logical processors sharing L3 cache.  */
+         int threads_l3;
+
+      if (shared <= 0)
+           {
+                 /* No shared L3 cache.  All we have is the L2 cache.  */
+             level = 2;
+             shared = core;
+             threads_l2 = 0;
+             threads_l3 = -1;
+           }
+         else
+           {
+             level = 3;
+             threads_l2 = 0;
+          threads_l3 = 0;
+           }
+
+         int i = 0;
+
+         /* Query until cache level 2 and 3 are enumerated.  */
+      int check = 0x1 | (threads_l3 == 0) << 1;
+         do
+           {
+                 __cpuid_count (4, i++, eax, ebx, ecx, edx);
+
+             switch ((eax >> 5) & 0x7)
+                   {
+                     default:
+                       break;
+                         case 2:
+                       if ((check & 0x1))
+                                 {
+                                   /* Get maximum number of logical processors
+                                         sharing L2 cache.  */
+                           threads_l2 = (eax >> 14) & 0x3ff;
+                           check &= ~0x1;
+                         }
+                       break;
+                     case 3:
+                               if ((check & (0x1 << 1)))
+                                 {
+                                   /* Get maximum number of logical processors
+                                 sharing L3 cache.  */
+                           threads_l3 = (eax >> 14) & 0x3ff;
+                           check &= ~(0x1 << 1);
+                         }
+                       break;
+                   }
+           }
+         while (check);
+
+        /* If max_cpuid >= 11, THREADS_L2/THREADS_L3 are the maximum
+           numbers of addressable IDs for logical processors sharing
+           the cache, instead of the maximum number of threads
+           sharing the cache.  */
+         if (max_cpuid >= 11)
+           {
+             /* Find the number of logical processors shipped in
+                one core and apply count mask.  */
+             i = 0;
+
+             /* Count SMT only if there is L3 cache.  Always count
+                core if there is no L3 cache.  */
+             int count = ((threads_l2 > 0 && level == 3)
+                          | ((threads_l3 > 0
+                              || (threads_l2 > 0 && level == 2)) << 1));
+
+             while (count)
+               {
+                 __cpuid_count (11, i++, eax, ebx, ecx, edx);
+
+                 int shipped = ebx & 0xff;
+                 int type = ecx & 0xff00;
+                 if (shipped == 0 || type == 0)
+                       break;
+                 else if (type == 0x100)
+                       {
+                         /* Count SMT.  */
+                         if ((count & 0x1))
+                           {
+                             int count_mask;
+
+                             /* Compute count mask.  */
+                             asm ("bsr %1, %0"
+                                  : "=r" (count_mask) : "g" (threads_l2));
+                             count_mask = ~(-1 << (count_mask + 1));
+                             threads_l2 = (shipped - 1) & count_mask;
+                             count &= ~0x1;
+                           }
+                       }
+                 else if (type == 0x200)
+                       {
+                         /* Count core.  */
+                         if ((count & (0x1 << 1)))
+                           {
+                             int count_mask;
+                             int threads_core
+                               = (level == 2 ? threads_l2 : threads_l3);
+
+                             /* Compute count mask.  */
+                             asm ("bsr %1, %0"
+                                  : "=r" (count_mask) : "g" (threads_core));
+                             count_mask = ~(-1 << (count_mask + 1));
+                             threads_core = (shipped - 1) & count_mask;
+                             if (level == 2)
+                                   threads_l2 = threads_core;
+                             else
+                                   threads_l3 = threads_core;
+                             count &= ~(0x1 << 1);
+                           }
+                       }
+               }
+           }
+         if (level == 2 && threads_l2 > 0)
+           threads = threads_l2 + 1;
+         if (level == 3 && threads_l3 > 0)
+           threads = threads_l3 + 1;
+
+         if (shared > 0 && threads > 0)
+               shared /= threads;
+    }

   if (cpu_features->data_cache_size != 0)
     data = cpu_features->data_cache_size;
