Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0
0002 /*
0003  * Check for extended topology enumeration cpuid leaf 0xb and if it
0004  * exists, use it for populating initial_apicid and cpu topology
0005  * detection.
0006  */
0007 
0008 #include <linux/cpu.h>
0009 #include <asm/apic.h>
0010 #include <asm/memtype.h>
0011 #include <asm/processor.h>
0012 
0013 #include "cpu.h"
0014 
0015 /* leaf 0xb SMT level */
0016 #define SMT_LEVEL   0
0017 
0018 /* extended topology sub-leaf types */
0019 #define INVALID_TYPE    0
0020 #define SMT_TYPE    1
0021 #define CORE_TYPE   2
0022 #define DIE_TYPE    5
0023 
0024 #define LEAFB_SUBTYPE(ecx)      (((ecx) >> 8) & 0xff)
0025 #define BITS_SHIFT_NEXT_LEVEL(eax)  ((eax) & 0x1f)
0026 #define LEVEL_MAX_SIBLINGS(ebx)     ((ebx) & 0xffff)
0027 
0028 unsigned int __max_die_per_package __read_mostly = 1;
0029 EXPORT_SYMBOL(__max_die_per_package);
0030 
0031 #ifdef CONFIG_SMP
0032 /*
0033  * Check if given CPUID extended topology "leaf" is implemented
0034  */
0035 static int check_extended_topology_leaf(int leaf)
0036 {
0037     unsigned int eax, ebx, ecx, edx;
0038 
0039     cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0040 
0041     if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
0042         return -1;
0043 
0044     return 0;
0045 }
0046 /*
0047  * Return best CPUID Extended Topology Leaf supported
0048  */
0049 static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
0050 {
0051     if (c->cpuid_level >= 0x1f) {
0052         if (check_extended_topology_leaf(0x1f) == 0)
0053             return 0x1f;
0054     }
0055 
0056     if (c->cpuid_level >= 0xb) {
0057         if (check_extended_topology_leaf(0xb) == 0)
0058             return 0xb;
0059     }
0060 
0061     return -1;
0062 }
0063 #endif
0064 
0065 int detect_extended_topology_early(struct cpuinfo_x86 *c)
0066 {
0067 #ifdef CONFIG_SMP
0068     unsigned int eax, ebx, ecx, edx;
0069     int leaf;
0070 
0071     leaf = detect_extended_topology_leaf(c);
0072     if (leaf < 0)
0073         return -1;
0074 
0075     set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
0076 
0077     cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0078     /*
0079      * initial apic id, which also represents 32-bit extended x2apic id.
0080      */
0081     c->initial_apicid = edx;
0082     smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
0083 #endif
0084     return 0;
0085 }
0086 
0087 /*
0088  * Check for extended topology enumeration cpuid leaf, and if it
0089  * exists, use it for populating initial_apicid and cpu topology
0090  * detection.
0091  */
0092 int detect_extended_topology(struct cpuinfo_x86 *c)
0093 {
0094 #ifdef CONFIG_SMP
0095     unsigned int eax, ebx, ecx, edx, sub_index;
0096     unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
0097     unsigned int core_select_mask, core_level_siblings;
0098     unsigned int die_select_mask, die_level_siblings;
0099     bool die_level_present = false;
0100     int leaf;
0101 
0102     leaf = detect_extended_topology_leaf(c);
0103     if (leaf < 0)
0104         return -1;
0105 
0106     /*
0107      * Populate HT related information from sub-leaf level 0.
0108      */
0109     cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0110     c->initial_apicid = edx;
0111     core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
0112     core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0113     die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0114     die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0115 
0116     sub_index = 1;
0117     do {
0118         cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
0119 
0120         /*
0121          * Check for the Core type in the implemented sub leaves.
0122          */
0123         if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
0124             core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0125             core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0126             die_level_siblings = core_level_siblings;
0127             die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0128         }
0129         if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
0130             die_level_present = true;
0131             die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0132             die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0133         }
0134 
0135         sub_index++;
0136     } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
0137 
0138     core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
0139     die_select_mask = (~(-1 << die_plus_mask_width)) >>
0140                 core_plus_mask_width;
0141 
0142     c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
0143                 ht_mask_width) & core_select_mask;
0144 
0145     if (die_level_present) {
0146         c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
0147                     core_plus_mask_width) & die_select_mask;
0148     }
0149 
0150     c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
0151                 die_plus_mask_width);
0152     /*
0153      * Reinit the apicid, now that we have extended initial_apicid.
0154      */
0155     c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
0156 
0157     c->x86_max_cores = (core_level_siblings / smp_num_siblings);
0158     __max_die_per_package = (die_level_siblings / core_level_siblings);
0159 #endif
0160     return 0;
0161 }