1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/cpu.h> 3 4 #include <asm/apic.h> 5 #include <asm/cpuid/api.h> 6 #include <asm/memtype.h> 7 #include <asm/processor.h> 8 9 #include "cpu.h" 10 11 enum topo_types { 12 INVALID_TYPE = 0, 13 SMT_TYPE = 1, 14 CORE_TYPE = 2, 15 MAX_TYPE_0B = 3, 16 MODULE_TYPE = 3, 17 AMD_CCD_TYPE = 3, 18 TILE_TYPE = 4, 19 AMD_SOCKET_TYPE = 4, 20 MAX_TYPE_80000026 = 5, 21 DIE_TYPE = 5, 22 DIEGRP_TYPE = 6, 23 MAX_TYPE_1F = 7, 24 }; 25 26 /* 27 * Use a lookup table for the case that there are future types > 6 which 28 * describe an intermediate domain level which does not exist today. 29 */ 30 static const unsigned int topo_domain_map_0b_1f[MAX_TYPE_1F] = { 31 [SMT_TYPE] = TOPO_SMT_DOMAIN, 32 [CORE_TYPE] = TOPO_CORE_DOMAIN, 33 [MODULE_TYPE] = TOPO_MODULE_DOMAIN, 34 [TILE_TYPE] = TOPO_TILE_DOMAIN, 35 [DIE_TYPE] = TOPO_DIE_DOMAIN, 36 [DIEGRP_TYPE] = TOPO_DIEGRP_DOMAIN, 37 }; 38 39 static const unsigned int topo_domain_map_80000026[MAX_TYPE_80000026] = { 40 [SMT_TYPE] = TOPO_SMT_DOMAIN, 41 [CORE_TYPE] = TOPO_CORE_DOMAIN, 42 [AMD_CCD_TYPE] = TOPO_TILE_DOMAIN, 43 [AMD_SOCKET_TYPE] = TOPO_DIE_DOMAIN, 44 }; 45 46 static inline bool topo_subleaf(struct topo_scan *tscan, u32 leaf, u32 subleaf, 47 unsigned int *last_dom) 48 { 49 unsigned int dom, maxtype; 50 const unsigned int *map; 51 struct { 52 // eax 53 u32 x2apic_shift : 5, // Number of bits to shift APIC ID right 54 // for the topology ID at the next level 55 : 27; // Reserved 56 // ebx 57 u32 num_processors : 16, // Number of processors at current level 58 : 16; // Reserved 59 // ecx 60 u32 level : 8, // Current topology level. Same as sub leaf number 61 type : 8, // Level type. If 0, invalid 62 : 16; // Reserved 63 // edx 64 u32 x2apic_id : 32; // X2APIC ID of the current logical processor 65 } sl; 66 67 switch (leaf) { 68 case 0x0b: maxtype = MAX_TYPE_0B; map = topo_domain_map_0b_1f; break; 69 case 0x1f: maxtype = MAX_TYPE_1F; map = topo_domain_map_0b_1f; break; 70 case 0x80000026: maxtype = MAX_TYPE_80000026; map = topo_domain_map_80000026; break; 71 default: return false; 72 } 73 74 cpuid_read_subleaf(leaf, subleaf, &sl); 75 76 if (!sl.num_processors || sl.type == INVALID_TYPE) 77 return false; 78 79 if (sl.type >= maxtype) { 80 pr_err_once("Topology: leaf 0x%x:%d Unknown domain type %u\n", 81 leaf, subleaf, sl.type); 82 /* 83 * It really would have been too obvious to make the domain 84 * type space sparse and leave a few reserved types between 85 * the points which might change instead of following the 86 * usual "this can be fixed in software" principle. 87 */ 88 dom = *last_dom + 1; 89 } else { 90 dom = map[sl.type]; 91 *last_dom = dom; 92 } 93 94 if (!dom) { 95 tscan->c->topo.initial_apicid = sl.x2apic_id; 96 } else if (tscan->c->topo.initial_apicid != sl.x2apic_id) { 97 pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf %d APIC ID mismatch %x != %x\n", 98 leaf, subleaf, tscan->c->topo.initial_apicid, sl.x2apic_id); 99 } 100 101 topology_set_dom(tscan, dom, sl.x2apic_shift, sl.num_processors); 102 return true; 103 } 104 105 static bool parse_topology_leaf(struct topo_scan *tscan, u32 leaf) 106 { 107 unsigned int last_dom; 108 u32 subleaf; 109 110 /* Read all available subleafs and populate the levels */ 111 for (subleaf = 0, last_dom = 0; topo_subleaf(tscan, leaf, subleaf, &last_dom); subleaf++); 112 113 /* If subleaf 0 failed to parse, give up */ 114 if (!subleaf) 115 return false; 116 117 /* 118 * There are machines in the wild which have shift 0 in the subleaf 119 * 0, but advertise 2 logical processors at that level. They are 120 * truly SMT. 121 */ 122 if (!tscan->dom_shifts[TOPO_SMT_DOMAIN] && tscan->dom_ncpus[TOPO_SMT_DOMAIN] > 1) { 123 unsigned int sft = get_count_order(tscan->dom_ncpus[TOPO_SMT_DOMAIN]); 124 125 pr_warn_once(FW_BUG "CPUID leaf 0x%x subleaf 0 has shift level 0 but %u CPUs. Fixing it up.\n", 126 leaf, tscan->dom_ncpus[TOPO_SMT_DOMAIN]); 127 topology_update_dom(tscan, TOPO_SMT_DOMAIN, sft, tscan->dom_ncpus[TOPO_SMT_DOMAIN]); 128 } 129 130 set_cpu_cap(tscan->c, X86_FEATURE_XTOPOLOGY); 131 return true; 132 } 133 134 bool cpu_parse_topology_ext(struct topo_scan *tscan) 135 { 136 /* Intel: Try leaf 0x1F first. */ 137 if (tscan->c->cpuid_level >= 0x1f && parse_topology_leaf(tscan, 0x1f)) 138 return true; 139 140 /* AMD: Try leaf 0x80000026 first. */ 141 if (tscan->c->extended_cpuid_level >= 0x80000026 && parse_topology_leaf(tscan, 0x80000026)) 142 return true; 143 144 /* Intel/AMD: Fall back to leaf 0xB if available */ 145 return tscan->c->cpuid_level >= 0x0b && parse_topology_leaf(tscan, 0x0b); 146 } 147