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/pat.h>
  11#include <asm/processor.h>
  12
  13/* leaf 0xb SMT level */
  14#define SMT_LEVEL       0
  15
  16/* leaf 0xb sub-leaf types */
  17#define INVALID_TYPE    0
  18#define SMT_TYPE        1
  19#define CORE_TYPE       2
  20
  21#define LEAFB_SUBTYPE(ecx)              (((ecx) >> 8) & 0xff)
  22#define BITS_SHIFT_NEXT_LEVEL(eax)      ((eax) & 0x1f)
  23#define LEVEL_MAX_SIBLINGS(ebx)         ((ebx) & 0xffff)
  24
  25int detect_extended_topology_early(struct cpuinfo_x86 *c)
  26{
  27#ifdef CONFIG_SMP
  28        unsigned int eax, ebx, ecx, edx;
  29
  30        if (c->cpuid_level < 0xb)
  31                return -1;
  32
  33        cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
  34
  35        /*
  36         * check if the cpuid leaf 0xb is actually implemented.
  37         */
  38        if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
  39                return -1;
  40
  41        set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
  42
  43        /*
  44         * initial apic id, which also represents 32-bit extended x2apic id.
  45         */
  46        c->initial_apicid = edx;
  47        smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
  48#endif
  49        return 0;
  50}
  51
  52/*
  53 * Check for extended topology enumeration cpuid leaf 0xb and if it
  54 * exists, use it for populating initial_apicid and cpu topology
  55 * detection.
  56 */
  57int detect_extended_topology(struct cpuinfo_x86 *c)
  58{
  59#ifdef CONFIG_SMP
  60        unsigned int eax, ebx, ecx, edx, sub_index;
  61        unsigned int ht_mask_width, core_plus_mask_width;
  62        unsigned int core_select_mask, core_level_siblings;
  63
  64        if (detect_extended_topology_early(c) < 0)
  65                return -1;
  66
  67        /*
  68         * Populate HT related information from sub-leaf level 0.
  69         */
  70        cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
  71        core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
  72        core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
  73
  74        sub_index = 1;
  75        do {
  76                cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
  77
  78                /*
  79                 * Check for the Core type in the implemented sub leaves.
  80                 */
  81                if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
  82                        core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
  83                        core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
  84                        break;
  85                }
  86
  87                sub_index++;
  88        } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
  89
  90        core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
  91
  92        c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
  93                                                 & core_select_mask;
  94        c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
  95        /*
  96         * Reinit the apicid, now that we have extended initial_apicid.
  97         */
  98        c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
  99
 100        c->x86_max_cores = (core_level_siblings / smp_num_siblings);
 101#endif
 102        return 0;
 103}
 104