1 // SPDX-License-Identifier: GPL-2.0
5 #include <asm/memtype.h>
6 #include <asm/processor.h>
10 static bool parse_8000_0008(struct topo_scan
*tscan
)
14 u32 cpu_nthreads
: 8, // Number of physical threads - 1
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
22 if (tscan
->c
->extended_cpuid_level
< 0x80000008)
25 cpuid_leaf_reg(0x80000008, CPUID_ECX
, &ecx
);
27 /* If the thread bits are 0, then get the shift value from ecx.cpu_nthreads */
28 sft
= ecx
.apicid_coreid_len
;
30 sft
= get_count_order(ecx
.cpu_nthreads
+ 1);
33 * cpu_nthreads describes the number of threads in the package
34 * sft is the number of APIC ID bits per package
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.
41 topology_update_dom(tscan
, TOPO_SMT_DOMAIN
, 0, 1);
42 topology_set_dom(tscan
, TOPO_CORE_DOMAIN
, sft
, ecx
.cpu_nthreads
+ 1);
46 static void store_node(struct topo_scan
*tscan
, u16 nr_nodes
, u16 node_id
)
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.
54 * Up to Fam 16h this does not work at all and the legacy node ID
57 tscan
->amd_nodes_per_pkg
= nr_nodes
;
58 tscan
->amd_node_id
= node_id
;
61 static bool parse_8000_001e(struct topo_scan
*tscan
, bool has_topoext
)
65 u32 ext_apic_id
: 32; // Extended APIC ID
67 u32 core_id
: 8, // Unique per-socket logical core unit ID
68 core_nthreads
: 8, // #Threads per core (zero-based)
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
78 if (!boot_cpu_has(X86_FEATURE_TOPOEXT
))
81 cpuid_leaf(0x8000001e, &leaf
);
83 tscan
->c
->topo
.initial_apicid
= leaf
.ext_apic_id
;
86 * If leaf 0xb is available, then the domain shifts are set
87 * already and nothing to do here. Only valid for family >= 0x17.
89 if (!has_topoext
&& tscan
->c
->x86
>= 0x17) {
91 * Leaf 0x80000008 set the CORE domain shift already.
92 * Update the SMT domain, but do not propagate it.
94 unsigned int nthreads
= leaf
.core_nthreads
+ 1;
96 topology_update_dom(tscan
, TOPO_SMT_DOMAIN
, get_count_order(nthreads
), nthreads
);
99 store_node(tscan
, leaf
.nnodes_per_socket
+ 1, leaf
.node_id
);
101 if (tscan
->c
->x86_vendor
== X86_VENDOR_AMD
) {
102 if (tscan
->c
->x86
== 0x15)
103 tscan
->c
->topo
.cu_id
= leaf
.core_id
;
105 cacheinfo_amd_init_llc_id(tscan
->c
, leaf
.node_id
);
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].
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
]);
117 cacheinfo_hygon_init_llc_id(tscan
->c
);
122 static void parse_fam10h_node_id(struct topo_scan
*tscan
)
133 if (!boot_cpu_has(X86_FEATURE_NODEID_MSR
))
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
;
141 static void legacy_set_llc(struct topo_scan
*tscan
)
143 unsigned int apicid
= tscan
->c
->topo
.initial_apicid
;
145 /* If none of the parsers set LLC ID then use the die ID for it. */
146 if (tscan
->c
->topo
.llc_id
== BAD_APICID
)
147 tscan
->c
->topo
.llc_id
= apicid
>> tscan
->dom_shifts
[TOPO_CORE_DOMAIN
];
150 static void topoext_fixup(struct topo_scan
*tscan
)
152 struct cpuinfo_x86
*c
= tscan
->c
;
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)
160 if (msr_set_bit(0xc0011005, 54) <= 0)
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");
170 static void parse_topology_amd(struct topo_scan
*tscan
)
172 bool has_topoext
= false;
175 * If the extended topology leaf 0x8000_001e is available
176 * try to get SMT, CORE, TILE, and DIE shifts from extended
177 * CPUID leaf 0x8000_0026 on supported processors first. If
178 * extended CPUID leaf 0x8000_0026 is not supported, try to
179 * get SMT and CORE shift from leaf 0xb first, then try to
180 * get the CORE shift from leaf 0x8000_0008.
182 if (cpu_feature_enabled(X86_FEATURE_TOPOEXT
))
183 has_topoext
= cpu_parse_topology_ext(tscan
);
185 if (!has_topoext
&& !parse_8000_0008(tscan
))
188 /* Prefer leaf 0x8000001e if available */
189 if (parse_8000_001e(tscan
, has_topoext
))
192 /* Try the NODEID MSR */
193 parse_fam10h_node_id(tscan
);
196 void cpu_parse_topology_amd(struct topo_scan
*tscan
)
198 tscan
->amd_nodes_per_pkg
= 1;
199 topoext_fixup(tscan
);
200 parse_topology_amd(tscan
);
201 legacy_set_llc(tscan
);
203 if (tscan
->amd_nodes_per_pkg
> 1)
204 set_cpu_cap(tscan
->c
, X86_FEATURE_AMD_DCM
);
207 void cpu_topology_fixup_amd(struct topo_scan
*tscan
)
209 struct cpuinfo_x86
*c
= tscan
->c
;
212 * Adjust the core_id relative to the node when there is more than
215 if (tscan
->c
->x86
< 0x17 && tscan
->amd_nodes_per_pkg
> 1)
216 c
->topo
.core_id
%= tscan
->dom_ncpus
[TOPO_CORE_DOMAIN
] / tscan
->amd_nodes_per_pkg
;