1 // SPDX-License-Identifier: GPL-2.0 2 #include <linux/cpu.h> 3 4 #include <asm/apic.h> 5 #include <asm/memtype.h> 6 #include <asm/msr.h> 7 #include <asm/processor.h> 8 9 #include "cpu.h" 10 11 static bool parse_8000_0008(struct topo_scan *tscan) 12 { 13 struct { 14 // ecx 15 u32 cpu_nthreads : 8, // Number of physical threads - 1 16 : 4, // Reserved 17 apicid_coreid_len : 4, // Number of thread core ID bits (shift) in APIC ID 18 perf_tsc_len : 2, // Performance time-stamp counter size 19 : 14; // Reserved 20 } ecx; 21 unsigned int sft; 22 23 if (tscan->c->extended_cpuid_level < 0x80000008) 24 return false; 25 26 cpuid_leaf_reg(0x80000008, CPUID_ECX, &ecx); 27 28 /* If the thread bits are 0, then get the shift value from ecx.cpu_nthreads */ 29 sft = ecx.apicid_coreid_len; 30 if (!sft) 31 sft = get_count_order(ecx.cpu_nthreads + 1); 32 33 /* 34 * cpu_nthreads describes the number of threads in the package 35 * sft is the number of APIC ID bits per package 36 * 37 * As the number of actual threads per core is not described in 38 * this leaf, just set the CORE domain shift and let the later 39 * parsers set SMT shift. Assume one thread per core by default 40 * which is correct if there are no other CPUID leafs to parse. 41 */ 42 topology_update_dom(tscan, TOPO_SMT_DOMAIN, 0, 1); 43 topology_set_dom(tscan, TOPO_CORE_DOMAIN, sft, ecx.cpu_nthreads + 1); 44 return true; 45 } 46 47 static void store_node(struct topo_scan *tscan, u16 nr_nodes, u16 node_id) 48 { 49 /* 50 * Starting with Fam 17h the DIE domain could probably be used to 51 * retrieve the node info on AMD/HYGON. Analysis of CPUID dumps 52 * suggests it's the topmost bit(s) of the CPU cores area, but 53 * that's guess work and neither enumerated nor documented. 54 * 55 * Up to Fam 16h this does not work at all and the legacy node ID 56 * has to be used. 57 */ 58 tscan->amd_nodes_per_pkg = nr_nodes; 59 tscan->amd_node_id = node_id; 60 } 61 62 static bool parse_8000_001e(struct topo_scan *tscan, bool has_topoext) 63 { 64 struct { 65 // eax 66 u32 ext_apic_id : 32; // Extended APIC ID 67 // ebx 68 u32 core_id : 8, // Unique per-socket logical core unit ID 69 core_nthreads : 8, // #Threads per core (zero-based) 70 : 16; // Reserved 71 // ecx 72 u32 node_id : 8, // Node (die) ID of invoking logical CPU 73 nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket 74 : 21; // Reserved 75 // edx 76 u32 : 32; // Reserved 77 } leaf; 78 79 if (!boot_cpu_has(X86_FEATURE_TOPOEXT)) 80 return false; 81 82 cpuid_leaf(0x8000001e, &leaf); 83 84 /* 85 * If leaf 0xb/0x26 is available, then the APIC ID and the domain 86 * shifts are set already. 87 */ 88 if (!has_topoext) { 89 tscan->c->topo.initial_apicid = leaf.ext_apic_id; 90 91 /* 92 * Leaf 0x8000008 sets the CORE domain shift but not the 93 * SMT domain shift. On CPUs with family >= 0x17, there 94 * might be hyperthreads. 95 */ 96 if (tscan->c->x86 >= 0x17) { 97 /* Update the SMT domain, but do not propagate it. */ 98 unsigned int nthreads = leaf.core_nthreads + 1; 99 100 topology_update_dom(tscan, TOPO_SMT_DOMAIN, 101 get_count_order(nthreads), nthreads); 102 } 103 } 104 105 store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id); 106 107 if (tscan->c->x86_vendor == X86_VENDOR_AMD) { 108 if (tscan->c->x86 == 0x15) 109 tscan->c->topo.cu_id = leaf.core_id; 110 111 cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id); 112 } else { 113 /* 114 * Package ID is ApicId[6..] on certain Hygon CPUs. See 115 * commit e0ceeae708ce for explanation. The topology info 116 * is screwed up: The package shift is always 6 and the 117 * node ID is bit [4:5]. 118 */ 119 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && tscan->c->x86_model <= 0x3) { 120 topology_set_dom(tscan, TOPO_CORE_DOMAIN, 6, 121 tscan->dom_ncpus[TOPO_CORE_DOMAIN]); 122 } 123 cacheinfo_hygon_init_llc_id(tscan->c); 124 } 125 return true; 126 } 127 128 static void parse_fam10h_node_id(struct topo_scan *tscan) 129 { 130 union { 131 struct { 132 u64 node_id : 3, 133 nodes_per_pkg : 3, 134 unused : 58; 135 }; 136 u64 msr; 137 } nid; 138 139 if (!boot_cpu_has(X86_FEATURE_NODEID_MSR)) 140 return; 141 142 rdmsrq(MSR_FAM10H_NODE_ID, nid.msr); 143 store_node(tscan, nid.nodes_per_pkg + 1, nid.node_id); 144 tscan->c->topo.llc_id = nid.node_id; 145 } 146 147 static void legacy_set_llc(struct topo_scan *tscan) 148 { 149 unsigned int apicid = tscan->c->topo.initial_apicid; 150 151 /* If none of the parsers set LLC ID then use the die ID for it. */ 152 if (tscan->c->topo.llc_id == BAD_APICID) 153 tscan->c->topo.llc_id = apicid >> tscan->dom_shifts[TOPO_CORE_DOMAIN]; 154 } 155 156 static void topoext_fixup(struct topo_scan *tscan) 157 { 158 struct cpuinfo_x86 *c = tscan->c; 159 u64 msrval; 160 161 /* Try to re-enable TopologyExtensions if switched off by BIOS */ 162 if (cpu_has(c, X86_FEATURE_TOPOEXT) || c->x86_vendor != X86_VENDOR_AMD || 163 c->x86 != 0x15 || c->x86_model < 0x10 || c->x86_model > 0x6f) 164 return; 165 166 if (msr_set_bit(0xc0011005, 54) <= 0) 167 return; 168 169 rdmsrq(0xc0011005, msrval); 170 if (msrval & BIT_64(54)) { 171 set_cpu_cap(c, X86_FEATURE_TOPOEXT); 172 pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n"); 173 } 174 } 175 176 static void parse_topology_amd(struct topo_scan *tscan) 177 { 178 bool has_topoext = false; 179 180 /* 181 * If the extended topology leaf 0x8000_001e is available 182 * try to get SMT, CORE, TILE, and DIE shifts from extended 183 * CPUID leaf 0x8000_0026 on supported processors first. If 184 * extended CPUID leaf 0x8000_0026 is not supported, try to 185 * get SMT and CORE shift from leaf 0xb first, then try to 186 * get the CORE shift from leaf 0x8000_0008. 187 */ 188 if (cpu_feature_enabled(X86_FEATURE_TOPOEXT)) 189 has_topoext = cpu_parse_topology_ext(tscan); 190 191 if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES)) 192 tscan->c->topo.cpu_type = cpuid_ebx(0x80000026); 193 194 if (!has_topoext && !parse_8000_0008(tscan)) 195 return; 196 197 /* Prefer leaf 0x8000001e if available */ 198 if (parse_8000_001e(tscan, has_topoext)) 199 return; 200 201 /* Try the NODEID MSR */ 202 parse_fam10h_node_id(tscan); 203 } 204 205 void cpu_parse_topology_amd(struct topo_scan *tscan) 206 { 207 tscan->amd_nodes_per_pkg = 1; 208 topoext_fixup(tscan); 209 parse_topology_amd(tscan); 210 legacy_set_llc(tscan); 211 212 if (tscan->amd_nodes_per_pkg > 1) 213 set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM); 214 } 215 216 void cpu_topology_fixup_amd(struct topo_scan *tscan) 217 { 218 struct cpuinfo_x86 *c = tscan->c; 219 220 /* 221 * Adjust the core_id relative to the node when there is more than 222 * one node. 223 */ 224 if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1) 225 c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg; 226 } 227