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