x86/cpu/topology: Retrieve cores per package from topology bitmaps
authorThomas Gleixner <tglx@linutronix.de>
Tue, 13 Feb 2024 21:06:10 +0000 (22:06 +0100)
committerThomas Gleixner <tglx@linutronix.de>
Thu, 15 Feb 2024 21:07:45 +0000 (22:07 +0100)
Similar to other sizing information the number of cores per package can be
established from the topology bitmap.

Provide a function for retrieving that information and replace the buggy
hack in the CPUID evaluation with it.

Signed-off-by: Thomas Gleixner <tglx@linutronix.de>
Tested-by: Michael Kelley <mhklinux@outlook.com>
Tested-by: Sohil Mehta <sohil.mehta@intel.com>
Link: https://lore.kernel.org/r/20240213210252.956858282@linutronix.de
arch/x86/kernel/cpu/topology.c
arch/x86/kernel/cpu/topology.h
arch/x86/kernel/cpu/topology_common.c

index 29759b4f7213629f5fc67d1bcd1702d252c6e8c5..7db9df50ada8d325f1b318353c2dafcd2ac9b3a9 100644 (file)
@@ -257,6 +257,49 @@ int topology_get_logical_id(u32 apicid, enum x86_topology_domains at_level)
 }
 EXPORT_SYMBOL_GPL(topology_get_logical_id);
 
+/**
+ * topology_unit_count - Retrieve the count of specified units at a given topology domain level
+ * @apicid:            The APIC ID which specifies the search range
+ * @which_units:       The domain level specifying the units to count
+ * @at_level:          The domain level at which @which_units have to be counted
+ *
+ * This returns the number of possible units according to the enumerated
+ * information.
+ *
+ * E.g. topology_count_units(apicid, TOPO_CORE_DOMAIN, TOPO_PKG_DOMAIN)
+ * counts the number of possible cores in the package to which @apicid
+ * belongs.
+ *
+ * @at_level must obviously be greater than @which_level to produce useful
+ * results.  If @at_level is equal to @which_units the result is
+ * unsurprisingly 1. If @at_level is less than @which_units the results
+ * is by definition undefined and the function returns 0.
+ */
+unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                enum x86_topology_domains at_level)
+{
+       /* Remove the bits below @at_level to get the proper level ID of @apicid */
+       unsigned int lvlid = topo_apicid(apicid, at_level);
+       unsigned int id, end, cnt = 0;
+
+       if (lvlid >= MAX_LOCAL_APIC)
+               return 0;
+       if (!test_bit(lvlid, apic_maps[at_level].map))
+               return 0;
+       if (which_units > at_level)
+               return 0;
+       if (which_units == at_level)
+               return 1;
+
+       /* Calculate the exclusive end */
+       end = lvlid + (1U << x86_topo_system.dom_shifts[at_level]);
+       /* Unfortunately there is no bitmap_weight_range() */
+       for (id = find_next_bit(apic_maps[which_units].map, end, lvlid);
+            id < end; id = find_next_bit(apic_maps[which_units].map, end, ++id))
+               cnt++;
+       return cnt;
+}
+
 #ifdef CONFIG_ACPI_HOTPLUG_CPU
 /**
  * topology_hotplug_apic - Handle a physical hotplugged APIC after boot
index 2a3c838b6044ded4034f0ca13944534a228fa13f..37326297f80c8f089abc1d140fdc04dbb0ddab3b 100644 (file)
@@ -53,4 +53,15 @@ static inline void topology_update_dom(struct topo_scan *tscan, enum x86_topolog
        tscan->dom_ncpus[dom] = ncpus;
 }
 
+#ifdef CONFIG_X86_LOCAL_APIC
+unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                enum x86_topology_domains at_level);
+#else
+static inline unsigned int topology_unit_count(u32 apicid, enum x86_topology_domains which_units,
+                                              enum x86_topology_domains at_level)
+{
+       return 1;
+}
+#endif
+
 #endif /* ARCH_X86_TOPOLOGY_H */
index c21a3871a8709477fcce54b150ab679663e4a447..a2c3f8f5886d73ef1eedeca269dc9f22f4c02597 100644 (file)
@@ -155,25 +155,15 @@ static void topo_set_ids(struct topo_scan *tscan)
        c->topo.core_id = (apicid & topo_domain_mask(TOPO_PKG_DOMAIN)) >>
                x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];
 
+       /* Maximum number of cores on this package */
+       c->x86_max_cores = topology_unit_count(apicid, TOPO_CORE_DOMAIN, TOPO_PKG_DOMAIN);
+
        c->topo.amd_node_id = tscan->amd_node_id;
 
        if (c->x86_vendor == X86_VENDOR_AMD)
                cpu_topology_fixup_amd(tscan);
 }
 
-static void topo_set_max_cores(struct topo_scan *tscan)
-{
-       /*
-        * Bug compatible for now. This is broken on hybrid systems:
-        * 8 cores SMT + 8 cores w/o SMT
-        * tscan.dom_ncpus[TOPO_DIEGRP_DOMAIN] = 24; 24 / 2 = 12 !!
-        *
-        * Cannot be fixed without further topology enumeration changes.
-        */
-       tscan->c->x86_max_cores = tscan->dom_ncpus[TOPO_DIEGRP_DOMAIN] >>
-               x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];
-}
-
 void cpu_parse_topology(struct cpuinfo_x86 *c)
 {
        unsigned int dom, cpu = smp_processor_id();
@@ -201,7 +191,6 @@ void cpu_parse_topology(struct cpuinfo_x86 *c)
        }
 
        topo_set_ids(&tscan);
-       topo_set_max_cores(&tscan);
 }
 
 void __init cpu_init_topology(struct cpuinfo_x86 *c)
@@ -223,7 +212,6 @@ void __init cpu_init_topology(struct cpuinfo_x86 *c)
        }
 
        topo_set_ids(&tscan);
-       topo_set_max_cores(&tscan);
 
        /*
         * AMD systems have Nodes per package which cannot be mapped to