linux/arch/x86/kernel/cpu/topology.c
<<
>>
Prefs
   1// SPDX-License-Identifier: GPL-2.0
   2/*
   3 * Check for extended topology enumeration cpuid leaf 0xb and if it
   4 * exists, use it for populating initial_apicid and cpu topology
   5 * detection.
   6 */
   7
   8#include <linux/cpu.h>
   9#include <asm/apic.h>
  10#include <asm/memtype.h>
  11#include <asm/processor.h>
  12
  13#include "cpu.h"
  14
  15/* leaf 0xb SMT level */
  16#define SMT_LEVEL       0
  17
  18/* extended topology sub-leaf types */
  19#define INVALID_TYPE    0
  20#define SMT_TYPE        1
  21#define CORE_TYPE       2
  22#define DIE_TYPE        5
  23
  24#define LEAFB_SUBTYPE(ecx)              (((ecx) >> 8) & 0xff)
  25#define BITS_SHIFT_NEXT_LEVEL(eax)      ((eax) & 0x1f)
  26#define LEVEL_MAX_SIBLINGS(ebx)         ((ebx) & 0xffff)
  27
  28unsigned int __max_die_per_package __read_mostly = 1;
  29EXPORT_SYMBOL(__max_die_per_package);
  30
  31#ifdef CONFIG_SMP
  32/*
  33 * Check if given CPUID extended topology "leaf" is implemented
  34 */
  35static int check_extended_topology_leaf(int leaf)
  36{
  37        unsigned int eax, ebx, ecx, edx;
  38
  39        cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
  40
  41        if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
  42                return -1;
  43
  44        return 0;
  45}
  46/*
  47 * Return best CPUID Extended Topology Leaf supported
  48 */
  49static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
  50{
  51        if (c->cpuid_level >= 0x1f) {
  52                if (check_extended_topology_leaf(0x1f) == 0)
  53                        return 0x1f;
  54        }
  55
  56        if (c->cpuid_level >= 0xb) {
  57                if (check_extended_topology_leaf(0xb) == 0)
  58                        return 0xb;
  59        }
  60
  61        return -1;
  62}
  63#endif
  64
  65int detect_extended_topology_early(struct cpuinfo_x86 *c)
  66{
  67#ifdef CONFIG_SMP
  68        unsigned int eax, ebx, ecx, edx;
  69        int leaf;
  70
  71        leaf = detect_extended_topology_leaf(c);
  72        if (leaf < 0)
  73                return -1;
  74
  75        set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
  76
  77        cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
  78        /*
  79         * initial apic id, which also represents 32-bit extended x2apic id.
  80         */
  81        c->initial_apicid = edx;
  82        smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
  83#endif
  84        return 0;
  85}
  86
  87/*
  88 * Check for extended topology enumeration cpuid leaf, and if it
  89 * exists, use it for populating initial_apicid and cpu topology
  90 * detection.
  91 */
  92int detect_extended_topology(struct cpuinfo_x86 *c)
  93{
  94#ifdef CONFIG_SMP
  95        unsigned int eax, ebx, ecx, edx, sub_index;
  96        unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
  97        unsigned int core_select_mask, core_level_siblings;
  98        unsigned int die_select_mask, die_level_siblings;
  99        bool die_level_present = false;
 100        int leaf;
 101
 102        leaf = detect_extended_topology_leaf(c);
 103        if (leaf < 0)
 104                return -1;
 105
 106        /*
 107         * Populate HT related information from sub-leaf level 0.
 108         */
 109        cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
 110        c->initial_apicid = edx;
 111        core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
 112        core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 113        die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 114        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 115
 116        sub_index = 1;
 117        do {
 118                cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
 119
 120                /*
 121                 * Check for the Core type in the implemented sub leaves.
 122                 */
 123                if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
 124                        core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 125                        core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 126                        die_level_siblings = core_level_siblings;
 127                        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 128                }
 129                if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
 130                        die_level_present = true;
 131                        die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 132                        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 133                }
 134
 135                sub_index++;
 136        } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
 137
 138        core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
 139        die_select_mask = (~(-1 << die_plus_mask_width)) >>
 140                                core_plus_mask_width;
 141
 142        c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
 143                                ht_mask_width) & core_select_mask;
 144
 145        if (die_level_present) {
 146                c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
 147                                        core_plus_mask_width) & die_select_mask;
 148        }
 149
 150        c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
 151                                die_plus_mask_width);
 152        /*
 153         * Reinit the apicid, now that we have extended initial_apicid.
 154         */
 155        c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 156
 157        c->x86_max_cores = (core_level_siblings / smp_num_siblings);
 158        __max_die_per_package = (die_level_siblings / core_level_siblings);
 159#endif
 160        return 0;
 161}
 162