return rc;
 }
 
+/*
+ * Calculate the size of the per-CPU data cache slice.  This can be
+ * used to estimate the size of the data cache slice that can be used
+ * by one CPU under ideal circumstances.  UNIFIED caches are counted
+ * in addition to DATA caches.  So, please consider code cache usage
+ * when use the result.
+ *
+ * Because the cache inclusive/non-inclusive information isn't
+ * available, we just use the size of the per-CPU slice of LLC to make
+ * the result more predictable across architectures.
+ */
+static void update_per_cpu_data_slice_size_cpu(unsigned int cpu)
+{
+       struct cpu_cacheinfo *ci;
+       struct cacheinfo *llc;
+       unsigned int nr_shared;
+
+       if (!last_level_cache_is_valid(cpu))
+               return;
+
+       ci = ci_cacheinfo(cpu);
+       llc = per_cpu_cacheinfo_idx(cpu, cache_leaves(cpu) - 1);
+
+       if (llc->type != CACHE_TYPE_DATA && llc->type != CACHE_TYPE_UNIFIED)
+               return;
+
+       nr_shared = cpumask_weight(&llc->shared_cpu_map);
+       if (nr_shared)
+               ci->per_cpu_data_slice_size = llc->size / nr_shared;
+}
+
+static void update_per_cpu_data_slice_size(bool cpu_online, unsigned int cpu)
+{
+       unsigned int icpu;
+
+       for_each_online_cpu(icpu) {
+               if (!cpu_online && icpu == cpu)
+                       continue;
+               update_per_cpu_data_slice_size_cpu(icpu);
+       }
+}
+
 static int cacheinfo_cpu_online(unsigned int cpu)
 {
        int rc = detect_cache_attributes(cpu);
                return rc;
        rc = cache_add_dev(cpu);
        if (rc)
-               free_cache_attributes(cpu);
+               goto err;
+       update_per_cpu_data_slice_size(true, cpu);
+       return 0;
+err:
+       free_cache_attributes(cpu);
        return rc;
 }
 
                cpu_cache_sysfs_exit(cpu);
 
        free_cache_attributes(cpu);
+       update_per_cpu_data_slice_size(false, cpu);
        return 0;
 }