root/arch/x86/kernel/cpu/topology.c

/* [<][>][^][v][top][bottom][index][help] */

DEFINITIONS

This source file includes following definitions.
  1. check_extended_topology_leaf
  2. detect_extended_topology_leaf
  3. detect_extended_topology_early
  4. detect_extended_topology

   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 #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
  29 unsigned int __max_die_per_package __read_mostly = 1;
  30 EXPORT_SYMBOL(__max_die_per_package);
  31 
  32 /*
  33  * Check if given CPUID extended toplogy "leaf" is implemented
  34  */
  35 static 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  */
  49 static 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 
  65 int 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  */
  92 int 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 }

/* [<][>][^][v][top][bottom][index][help] */