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
parse_8000_0008(struct topo_scan * tscan)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
store_node(struct topo_scan * tscan,u16 nr_nodes,u16 node_id)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
parse_8000_001e(struct topo_scan * tscan,bool has_topoext)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 tscan->c->topo.initial_apicid = leaf.ext_apic_id;
85
86 /*
87 * If leaf 0xb is available, then the domain shifts are set
88 * already and nothing to do here. Only valid for family >= 0x17.
89 */
90 if (!has_topoext && tscan->c->x86 >= 0x17) {
91 /*
92 * Leaf 0x80000008 set the CORE domain shift already.
93 * Update the SMT domain, but do not propagate it.
94 */
95 unsigned int nthreads = leaf.core_nthreads + 1;
96
97 topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads);
98 }
99
100 store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
101
102 if (tscan->c->x86_vendor == X86_VENDOR_AMD) {
103 if (tscan->c->x86 == 0x15)
104 tscan->c->topo.cu_id = leaf.core_id;
105
106 cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id);
107 } else {
108 /*
109 * Package ID is ApicId[6..] on certain Hygon CPUs. See
110 * commit e0ceeae708ce for explanation. The topology info
111 * is screwed up: The package shift is always 6 and the
112 * node ID is bit [4:5].
113 */
114 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && tscan->c->x86_model <= 0x3) {
115 topology_set_dom(tscan, TOPO_CORE_DOMAIN, 6,
116 tscan->dom_ncpus[TOPO_CORE_DOMAIN]);
117 }
118 cacheinfo_hygon_init_llc_id(tscan->c);
119 }
120 return true;
121 }
122
parse_fam10h_node_id(struct topo_scan * tscan)123 static void parse_fam10h_node_id(struct topo_scan *tscan)
124 {
125 union {
126 struct {
127 u64 node_id : 3,
128 nodes_per_pkg : 3,
129 unused : 58;
130 };
131 u64 msr;
132 } nid;
133
134 if (!boot_cpu_has(X86_FEATURE_NODEID_MSR))
135 return;
136
137 rdmsrq(MSR_FAM10H_NODE_ID, nid.msr);
138 store_node(tscan, nid.nodes_per_pkg + 1, nid.node_id);
139 tscan->c->topo.llc_id = nid.node_id;
140 }
141
legacy_set_llc(struct topo_scan * tscan)142 static void legacy_set_llc(struct topo_scan *tscan)
143 {
144 unsigned int apicid = tscan->c->topo.initial_apicid;
145
146 /* If none of the parsers set LLC ID then use the die ID for it. */
147 if (tscan->c->topo.llc_id == BAD_APICID)
148 tscan->c->topo.llc_id = apicid >> tscan->dom_shifts[TOPO_CORE_DOMAIN];
149 }
150
topoext_fixup(struct topo_scan * tscan)151 static void topoext_fixup(struct topo_scan *tscan)
152 {
153 struct cpuinfo_x86 *c = tscan->c;
154 u64 msrval;
155
156 /* Try to re-enable TopologyExtensions if switched off by BIOS */
157 if (cpu_has(c, X86_FEATURE_TOPOEXT) || c->x86_vendor != X86_VENDOR_AMD ||
158 c->x86 != 0x15 || c->x86_model < 0x10 || c->x86_model > 0x6f)
159 return;
160
161 if (msr_set_bit(0xc0011005, 54) <= 0)
162 return;
163
164 rdmsrq(0xc0011005, msrval);
165 if (msrval & BIT_64(54)) {
166 set_cpu_cap(c, X86_FEATURE_TOPOEXT);
167 pr_info_once(FW_INFO "CPU: Re-enabling disabled Topology Extensions Support.\n");
168 }
169 }
170
parse_topology_amd(struct topo_scan * tscan)171 static void parse_topology_amd(struct topo_scan *tscan)
172 {
173 bool has_topoext = false;
174
175 /*
176 * If the extended topology leaf 0x8000_001e is available
177 * try to get SMT, CORE, TILE, and DIE shifts from extended
178 * CPUID leaf 0x8000_0026 on supported processors first. If
179 * extended CPUID leaf 0x8000_0026 is not supported, try to
180 * get SMT and CORE shift from leaf 0xb first, then try to
181 * get the CORE shift from leaf 0x8000_0008.
182 */
183 if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
184 has_topoext = cpu_parse_topology_ext(tscan);
185
186 if (cpu_feature_enabled(X86_FEATURE_AMD_HTR_CORES))
187 tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
188
189 if (!has_topoext && !parse_8000_0008(tscan))
190 return;
191
192 /* Prefer leaf 0x8000001e if available */
193 if (parse_8000_001e(tscan, has_topoext))
194 return;
195
196 /* Try the NODEID MSR */
197 parse_fam10h_node_id(tscan);
198 }
199
cpu_parse_topology_amd(struct topo_scan * tscan)200 void cpu_parse_topology_amd(struct topo_scan *tscan)
201 {
202 tscan->amd_nodes_per_pkg = 1;
203 topoext_fixup(tscan);
204 parse_topology_amd(tscan);
205 legacy_set_llc(tscan);
206
207 if (tscan->amd_nodes_per_pkg > 1)
208 set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
209 }
210
cpu_topology_fixup_amd(struct topo_scan * tscan)211 void cpu_topology_fixup_amd(struct topo_scan *tscan)
212 {
213 struct cpuinfo_x86 *c = tscan->c;
214
215 /*
216 * Adjust the core_id relative to the node when there is more than
217 * one node.
218 */
219 if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1)
220 c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg;
221 }
222