x86/cacheinfo: Delete global num_cache_leaves
authorRicardo Neri <ricardo.neri-calderon@linux.intel.com>
Thu, 28 Nov 2024 00:22:47 +0000 (16:22 -0800)
committerBorislav Petkov (AMD) <bp@alien8.de>
Fri, 6 Dec 2024 12:13:36 +0000 (13:13 +0100)
Linux remembers cpu_cachinfo::num_leaves per CPU, but x86 initializes all
CPUs from the same global "num_cache_leaves".

This is erroneous on systems such as Meteor Lake, where each CPU has a
distinct num_leaves value. Delete the global "num_cache_leaves" and
initialize num_leaves on each CPU.

init_cache_level() no longer needs to set num_leaves. Also, it never had to
set num_levels as it is unnecessary in x86. Keep checking for zero cache
leaves. Such condition indicates a bug.

  [ bp: Cleanup. ]

Signed-off-by: Ricardo Neri <ricardo.neri-calderon@linux.intel.com>
Signed-off-by: Borislav Petkov (AMD) <bp@alien8.de>
Cc: stable@vger.kernel.org # 6.3+
Link: https://lore.kernel.org/r/20241128002247.26726-3-ricardo.neri-calderon@linux.intel.com
arch/x86/kernel/cpu/cacheinfo.c

index 392d09c936d60c4d5775bca0b044fe738e0c9937..e6fa03ed9172c09a1622ea393a20d12c7fb7afa4 100644 (file)
@@ -178,8 +178,6 @@ struct _cpuid4_info_regs {
        struct amd_northbridge *nb;
 };
 
-static unsigned short num_cache_leaves;
-
 /* AMD doesn't have CPUID4. Emulate it here to report the same
    information to the user.  This makes some assumptions about the machine:
    L2 not shared, no SMT etc. that is currently true on AMD CPUs.
@@ -717,20 +715,23 @@ void cacheinfo_hygon_init_llc_id(struct cpuinfo_x86 *c)
 
 void init_amd_cacheinfo(struct cpuinfo_x86 *c)
 {
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
 
        if (boot_cpu_has(X86_FEATURE_TOPOEXT)) {
-               num_cache_leaves = find_num_cache_leaves(c);
+               ci->num_leaves = find_num_cache_leaves(c);
        } else if (c->extended_cpuid_level >= 0x80000006) {
                if (cpuid_edx(0x80000006) & 0xf000)
-                       num_cache_leaves = 4;
+                       ci->num_leaves = 4;
                else
-                       num_cache_leaves = 3;
+                       ci->num_leaves = 3;
        }
 }
 
 void init_hygon_cacheinfo(struct cpuinfo_x86 *c)
 {
-       num_cache_leaves = find_num_cache_leaves(c);
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
+
+       ci->num_leaves = find_num_cache_leaves(c);
 }
 
 void init_intel_cacheinfo(struct cpuinfo_x86 *c)
@@ -740,21 +741,21 @@ void init_intel_cacheinfo(struct cpuinfo_x86 *c)
        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
        unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
        unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(c->cpu_index);
 
        if (c->cpuid_level > 3) {
-               static int is_initialized;
-
-               if (is_initialized == 0) {
-                       /* Init num_cache_leaves from boot CPU */
-                       num_cache_leaves = find_num_cache_leaves(c);
-                       is_initialized++;
-               }
+               /*
+                * There should be at least one leaf. A non-zero value means
+                * that the number of leaves has been initialized.
+                */
+               if (!ci->num_leaves)
+                       ci->num_leaves = find_num_cache_leaves(c);
 
                /*
                 * Whenever possible use cpuid(4), deterministic cache
                 * parameters cpuid leaf to find the cache details
                 */
-               for (i = 0; i < num_cache_leaves; i++) {
+               for (i = 0; i < ci->num_leaves; i++) {
                        struct _cpuid4_info_regs this_leaf = {};
                        int retval;
 
@@ -790,14 +791,14 @@ void init_intel_cacheinfo(struct cpuinfo_x86 *c)
         * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
         * trace cache
         */
-       if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
+       if ((!ci->num_leaves || c->x86 == 15) && c->cpuid_level > 1) {
                /* supports eax=2  call */
                int j, n;
                unsigned int regs[4];
                unsigned char *dp = (unsigned char *)regs;
                int only_trace = 0;
 
-               if (num_cache_leaves != 0 && c->x86 == 15)
+               if (ci->num_leaves && c->x86 == 15)
                        only_trace = 1;
 
                /* Number of times to iterate */
@@ -991,14 +992,12 @@ static void ci_leaf_init(struct cacheinfo *this_leaf,
 
 int init_cache_level(unsigned int cpu)
 {
-       struct cpu_cacheinfo *this_cpu_ci = get_cpu_cacheinfo(cpu);
+       struct cpu_cacheinfo *ci = get_cpu_cacheinfo(cpu);
 
-       if (!num_cache_leaves)
+       /* There should be at least one leaf. */
+       if (!ci->num_leaves)
                return -ENOENT;
-       if (!this_cpu_ci)
-               return -EINVAL;
-       this_cpu_ci->num_levels = 3;
-       this_cpu_ci->num_leaves = num_cache_leaves;
+
        return 0;
 }