x86/cpu: Add legacy topology parser
authorThomas Gleixner <tglx@linutronix.de>
Tue, 13 Feb 2024 21:04:03 +0000 (22:04 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 15 Feb 2024 21:07:37 +0000 (22:07 +0100)
The legacy topology detection via CPUID leaf 4, which provides the number
of cores in the package and CPUID leaf 1 which provides the number of
logical CPUs in case that FEATURE_HT is enabled and the CMP_LEGACY feature
is not set, is shared for Intel, Centaur and Zhaoxin CPUs.

Lift the code from common.c without the early detection hack and provide it
as common fallback mechanism.

Will be utilized in later changes.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Juergen Gross <jgross@suse.com>
Tested-by: Sohil Mehta <sohil.mehta@intel.com>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Tested-by: Zhang Rui <rui.zhang@intel.com>
Tested-by: Wang Wendy <wendy.wang@intel.com>
Tested-by: K Prateek Nayak <kprateek.nayak@amd.com>
Link: https://lore.kernel.org/r/20240212153624.644448852@linutronix.de
arch/x86/kernel/cpu/common.c
arch/x86/kernel/cpu/topology.h
arch/x86/kernel/cpu/topology_common.c

index d674e7bdd6e4a688d475f5a252df5b04d54e14f7..004ae9cfcb6398b3c448661ed17a2d4b9eb2aed5 100644 (file)
@@ -892,6 +892,9 @@ void detect_ht(struct cpuinfo_x86 *c)
 #ifdef CONFIG_SMP
        int index_msb, core_bits;
 
+       if (topo_is_converted(c))
+               return;
+
        if (detect_ht_early(c) < 0)
                return;
 
index 99c94c519b5dc33bfa668bdcb9c2bb67abba128b..934a100b9fe63d76a89cd931c82382570bf20751 100644 (file)
@@ -6,6 +6,9 @@ struct topo_scan {
        struct cpuinfo_x86      *c;
        unsigned int            dom_shifts[TOPO_MAX_DOMAIN];
        unsigned int            dom_ncpus[TOPO_MAX_DOMAIN];
+
+       /* Legacy CPUID[1]:EBX[23:16] number of logical processors */
+       unsigned int            ebx1_nproc_shift;
 };
 
 bool topo_is_converted(struct cpuinfo_x86 *c);
index 873d7c3fe7acb22f8ff76a0659243ce5f51f64fb..b0ff1fc84a13da5badf197c95f2f0f84d53944de 100644 (file)
@@ -24,6 +24,48 @@ void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
        }
 }
 
+static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)
+{
+       struct {
+               u32     cache_type      :  5,
+                       unused          : 21,
+                       ncores          :  6;
+       } eax;
+
+       if (c->cpuid_level < 4)
+               return 1;
+
+       cpuid_subleaf_reg(4, 0, CPUID_EAX, &eax);
+       if (!eax.cache_type)
+               return 1;
+
+       return eax.ncores + 1;
+}
+
+static void __maybe_unused parse_legacy(struct topo_scan *tscan)
+{
+       unsigned int cores, core_shift, smt_shift = 0;
+       struct cpuinfo_x86 *c = tscan->c;
+
+       cores = parse_num_cores_legacy(c);
+       core_shift = get_count_order(cores);
+
+       if (cpu_has(c, X86_FEATURE_HT)) {
+               if (!WARN_ON_ONCE(tscan->ebx1_nproc_shift < core_shift))
+                       smt_shift = tscan->ebx1_nproc_shift - core_shift;
+               /*
+                * The parser expects leaf 0xb/0x1f format, which means
+                * the number of logical processors at core level is
+                * counting threads.
+                */
+               core_shift += smt_shift;
+               cores <<= smt_shift;
+       }
+
+       topology_set_dom(tscan, TOPO_SMT_DOMAIN, smt_shift, 1U << smt_shift);
+       topology_set_dom(tscan, TOPO_CORE_DOMAIN, core_shift, cores);
+}
+
 bool topo_is_converted(struct cpuinfo_x86 *c)
 {
        /* Temporary until everything is converted over. */
@@ -47,7 +89,7 @@ static bool fake_topology(struct topo_scan *tscan)
         * which has useless CPUID information.
         */
        topology_set_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);
-       topology_set_dom(tscan, TOPO_CORE_DOMAIN, 1, 1);
+       topology_set_dom(tscan, TOPO_CORE_DOMAIN, 0, 1);
 
        return tscan->c->cpuid_level < 1 || xen_pv_domain();
 }
@@ -88,6 +130,8 @@ static void parse_topology(struct topo_scan *tscan, bool early)
        /* The above is sufficient for UP */
        if (!IS_ENABLED(CONFIG_SMP))
                return;
+
+       tscan->ebx1_nproc_shift = get_count_order(ebx.nproc);
 }
 
 static void topo_set_ids(struct topo_scan *tscan)