x86/CPU/AMD: Calculate last level cache ID from number of sharing threads
authorSuravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Fri, 27 Apr 2018 21:34:37 +0000 (16:34 -0500)
committerThomas Gleixner <tglx@linutronix.de>
Sun, 6 May 2018 10:49:15 +0000 (12:49 +0200)
Last Level Cache ID can be calculated from the number of threads sharing
the cache, which is available from CPUID Fn0x8000001D (Cache Properties).
This is used to left-shift the APIC ID to derive LLC ID.

Therefore, default to this method unless the APIC ID enumeration does not
follow the scheme.

Signed-off-by: Suravee Suthikulpanit <suravee.suthikulpanit@amd.com>
Signed-off-by: Borislav Petkov <bp@suse.de>
Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Link: http://lkml.kernel.org/r/1524864877-111962-5-git-send-email-suravee.suthikulpanit@amd.com
arch/x86/include/asm/cacheinfo.h [new file with mode: 0644]
arch/x86/kernel/cpu/amd.c
arch/x86/kernel/cpu/cacheinfo.c

diff --git a/arch/x86/include/asm/cacheinfo.h b/arch/x86/include/asm/cacheinfo.h
new file mode 100644 (file)
index 0000000..e958e28
--- /dev/null
@@ -0,0 +1,7 @@
+/* SPDX-License-Identifier: GPL-2.0 */
+#ifndef _ASM_X86_CACHEINFO_H
+#define _ASM_X86_CACHEINFO_H
+
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id);
+
+#endif /* _ASM_X86_CACHEINFO_H */
index a37a83809665450ce5438a92a8f47f0ba8418e6c..bf27246bb7bd444bacf989bd13346cfd4d7d2a02 100644 (file)
@@ -9,6 +9,7 @@
 #include <linux/random.h>
 #include <asm/processor.h>
 #include <asm/apic.h>
+#include <asm/cacheinfo.h>
 #include <asm/cpu.h>
 #include <asm/smp.h>
 #include <asm/pci-direct.h>
@@ -343,22 +344,8 @@ static void amd_get_topology(struct cpuinfo_x86 *c)
                                c->x86_max_cores /= smp_num_siblings;
                }
 
-               /*
-                * We may have multiple LLCs if L3 caches exist, so check if we
-                * have an L3 cache by looking at the L3 cache CPUID leaf.
-                */
-               if (cpuid_edx(0x80000006)) {
-                       if (c->x86 == 0x17) {
-                               /*
-                                * LLC is at the core complex level.
-                                * Core complex id is ApicId[3].
-                                */
-                               per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
-                       } else {
-                               /* LLC is at the node level. */
-                               per_cpu(cpu_llc_id, cpu) = node_id;
-                       }
-               }
+               cacheinfo_amd_init_llc_id(c, cpu, node_id);
+
        } else if (cpu_has(c, X86_FEATURE_NODEID_MSR)) {
                u64 value;
 
index 54d04d5741481164fea1045eb9a96b752ae452c2..a2e03c9401a126f72b82291ae0e6444dfc85577d 100644 (file)
@@ -637,6 +637,45 @@ static int find_num_cache_leaves(struct cpuinfo_x86 *c)
        return i;
 }
 
+void cacheinfo_amd_init_llc_id(struct cpuinfo_x86 *c, int cpu, u8 node_id)
+{
+       /*
+        * We may have multiple LLCs if L3 caches exist, so check if we
+        * have an L3 cache by looking at the L3 cache CPUID leaf.
+        */
+       if (!cpuid_edx(0x80000006))
+               return;
+
+       if (c->x86 < 0x17) {
+               /* LLC is at the node level. */
+               per_cpu(cpu_llc_id, cpu) = node_id;
+       } else if (c->x86 == 0x17 &&
+                  c->x86_model >= 0 && c->x86_model <= 0x1F) {
+               /*
+                * LLC is at the core complex level.
+                * Core complex ID is ApicId[3] for these processors.
+                */
+               per_cpu(cpu_llc_id, cpu) = c->apicid >> 3;
+       } else {
+               /*
+                * LLC ID is calculated from the number of threads sharing the
+                * cache.
+                * */
+               u32 eax, ebx, ecx, edx, num_sharing_cache = 0;
+               u32 llc_index = find_num_cache_leaves(c) - 1;
+
+               cpuid_count(0x8000001d, llc_index, &eax, &ebx, &ecx, &edx);
+               if (eax)
+                       num_sharing_cache = ((eax >> 14) & 0xfff) + 1;
+
+               if (num_sharing_cache) {
+                       int bits = get_count_order(num_sharing_cache) - 1;
+
+                       per_cpu(cpu_llc_id, cpu) = c->apicid >> bits;
+               }
+       }
+}
+
 void init_amd_cacheinfo(struct cpuinfo_x86 *c)
 {