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 29 /* 30 * Check if given CPUID extended topology "leaf" is implemented 31 */ 32 static int check_extended_topology_leaf(int leaf) 33 { 34 unsigned int eax, ebx, ecx, edx; 35 36 cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx); 37 38 if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) 39 return -1; 40 41 return 0; 42 } 43 /* 44 * Return best CPUID Extended Topology Leaf supported 45 */ 46 static int detect_extended_topology_leaf(struct cpuinfo_x86 *c) 47 { 48 if (c->cpuid_level >= 0x1f) { 49 if (check_extended_topology_leaf(0x1f) == 0) 50 return 0x1f; 51 } 52 53 if (c->cpuid_level >= 0xb) { 54 if (check_extended_topology_leaf(0xb) == 0) 55 return 0xb; 56 } 57 58 return -1; 59 } 60 #endif 61 62 /* 63 * Check for extended topology enumeration cpuid leaf, and if it 64 * exists, use it for populating initial_apicid and cpu topology 65 * detection. 66 */ 67 int detect_extended_topology(struct cpuinfo_x86 *c) 68 { 69 #ifdef CONFIG_SMP 70 unsigned int eax, ebx, ecx, edx, sub_index; 71 unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width; 72 unsigned int core_select_mask, core_level_siblings; 73 unsigned int die_select_mask, die_level_siblings; 74 unsigned int pkg_mask_width; 75 bool die_level_present = false; 76 int leaf; 77 78 leaf = detect_extended_topology_leaf(c); 79 if (leaf < 0) 80 return -1; 81 82 /* 83 * Populate HT related information from sub-leaf level 0. 84 */ 85 cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx); 86 c->topo.initial_apicid = edx; 87 core_level_siblings = LEVEL_MAX_SIBLINGS(ebx); 88 smp_num_siblings = max_t(int, smp_num_siblings, LEVEL_MAX_SIBLINGS(ebx)); 89 core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 90 die_level_siblings = LEVEL_MAX_SIBLINGS(ebx); 91 pkg_mask_width = die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 92 93 sub_index = 1; 94 while (true) { 95 cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx); 96 97 /* 98 * Check for the Core type in the implemented sub leaves. 99 */ 100 if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) { 101 core_level_siblings = LEVEL_MAX_SIBLINGS(ebx); 102 core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 103 die_level_siblings = core_level_siblings; 104 die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 105 } 106 if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) { 107 die_level_present = true; 108 die_level_siblings = LEVEL_MAX_SIBLINGS(ebx); 109 die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 110 } 111 112 if (LEAFB_SUBTYPE(ecx) != INVALID_TYPE) 113 pkg_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); 114 else 115 break; 116 117 sub_index++; 118 } 119 120 core_select_mask = (~(-1 << pkg_mask_width)) >> ht_mask_width; 121 die_select_mask = (~(-1 << die_plus_mask_width)) >> 122 core_plus_mask_width; 123 124 c->topo.core_id = apic->phys_pkg_id(c->topo.initial_apicid, 125 ht_mask_width) & core_select_mask; 126 127 if (die_level_present) { 128 c->topo.die_id = apic->phys_pkg_id(c->topo.initial_apicid, 129 core_plus_mask_width) & die_select_mask; 130 } 131 132 c->topo.pkg_id = apic->phys_pkg_id(c->topo.initial_apicid, pkg_mask_width); 133 /* 134 * Reinit the apicid, now that we have extended initial_apicid. 135 */ 136 c->topo.apicid = apic->phys_pkg_id(c->topo.initial_apicid, 0); 137 138 c->x86_max_cores = (core_level_siblings / smp_num_siblings); 139 __max_die_per_package = (die_level_siblings / core_level_siblings); 140 #endif 141 return 0; 142 } 143