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
  28#ifdef CONFIG_SMP
  29unsigned int __max_die_per_package __read_mostly = 1;
  30EXPORT_SYMBOL(__max_die_per_package);
  31
  32/*
  33 * Check if given CPUID extended toplogy "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 Toplogy 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        int leaf;
 100
 101        leaf = detect_extended_topology_leaf(c);
 102        if (leaf < 0)
 103                return -1;
 104
 105        /*
 106         * Populate HT related information from sub-leaf level 0.
 107         */
 108        cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
 109        c->initial_apicid = edx;
 110        core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
 111        core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 112        die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 113        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 114
 115        sub_index = 1;
 116        do {
 117                cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
 118
 119                /*
 120                 * Check for the Core type in the implemented sub leaves.
 121                 */
 122                if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
 123                        core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 124                        core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 125                        die_level_siblings = core_level_siblings;
 126                        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 127                }
 128                if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
 129                        die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
 130                        die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
 131                }
 132
 133                sub_index++;
 134        } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
 135
 136        core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
 137        die_select_mask = (~(-1 << die_plus_mask_width)) >>
 138                                core_plus_mask_width;
 139
 140        c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
 141                                ht_mask_width) & core_select_mask;
 142        c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
 143                                core_plus_mask_width) & die_select_mask;
 144        c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
 145                                die_plus_mask_width);
 146        /*
 147         * Reinit the apicid, now that we have extended initial_apicid.
 148         */
 149        c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
 150
 151        c->x86_max_cores = (core_level_siblings / smp_num_siblings);
 152        __max_die_per_package = (die_level_siblings / core_level_siblings);
 153#endif
 154        return 0;
 155}
 156