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