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);
32 topology_set_dom(tscan, TOPO_SMT_DOMAIN, sft, ecx.cpu_nthreads + 1);
36 static void store_node(struct topo_scan *tscan, unsigned int nr_nodes, u16 node_id)
39 * Starting with Fam 17h the DIE domain could probably be used to
40 * retrieve the node info on AMD/HYGON. Analysis of CPUID dumps
41 * suggests it's the topmost bit(s) of the CPU cores area, but
42 * that's guess work and neither enumerated nor documented.
44 * Up to Fam 16h this does not work at all and the legacy node ID
47 tscan->amd_nodes_per_pkg = nr_nodes;
48 tscan->amd_node_id = node_id;
51 static bool parse_8000_001e(struct topo_scan *tscan, bool has_0xb)
55 u32 ext_apic_id : 32; // Extended APIC ID
57 u32 core_id : 8, // Unique per-socket logical core unit ID
58 core_nthreads : 8, // #Threads per core (zero-based)
61 u32 node_id : 8, // Node (die) ID of invoking logical CPU
62 nnodes_per_socket : 3, // #nodes in invoking logical CPU's package/socket
68 if (!boot_cpu_has(X86_FEATURE_TOPOEXT))
71 cpuid_leaf(0x8000001e, &leaf);
73 tscan->c->topo.initial_apicid = leaf.ext_apic_id;
76 * If leaf 0xb is available, then SMT shift is set already. If not
77 * take it from ecx.threads_per_core and use topo_update_dom() -
78 * topology_set_dom() would propagate and overwrite the already
79 * propagated CORE level.
82 unsigned int nthreads = leaf.core_nthreads + 1;
84 topology_update_dom(tscan, TOPO_SMT_DOMAIN, get_count_order(nthreads), nthreads);
87 store_node(tscan, leaf.nnodes_per_socket + 1, leaf.node_id);
89 if (tscan->c->x86_vendor == X86_VENDOR_AMD) {
90 if (tscan->c->x86 == 0x15)
91 tscan->c->topo.cu_id = leaf.core_id;
93 cacheinfo_amd_init_llc_id(tscan->c, leaf.node_id);
96 * Package ID is ApicId[6..] on certain Hygon CPUs. See
97 * commit e0ceeae708ce for explanation. The topology info
98 * is screwed up: The package shift is always 6 and the
99 * node ID is bit [4:5].
101 if (!boot_cpu_has(X86_FEATURE_HYPERVISOR) && tscan->c->x86_model <= 0x3) {
102 topology_set_dom(tscan, TOPO_CORE_DOMAIN, 6,
103 tscan->dom_ncpus[TOPO_CORE_DOMAIN]);
105 cacheinfo_hygon_init_llc_id(tscan->c);
110 static bool parse_fam10h_node_id(struct topo_scan *tscan)
121 if (!boot_cpu_has(X86_FEATURE_NODEID_MSR))
124 rdmsrl(MSR_FAM10H_NODE_ID, nid.msr);
125 store_node(tscan, nid.nodes_per_pkg + 1, nid.node_id);
126 tscan->c->topo.llc_id = nid.node_id;
130 static void legacy_set_llc(struct topo_scan *tscan)
132 unsigned int apicid = tscan->c->topo.initial_apicid;
134 /* parse_8000_0008() set everything up except llc_id */
135 tscan->c->topo.llc_id = apicid >> tscan->dom_shifts[TOPO_CORE_DOMAIN];
138 static void parse_topology_amd(struct topo_scan *tscan)
140 bool has_0xb = false;
143 * If the extended topology leaf 0x8000_001e is available
144 * try to get SMT and CORE shift from leaf 0xb first, then
145 * try to get the CORE shift from leaf 0x8000_0008.
147 if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
148 has_0xb = cpu_parse_topology_ext(tscan);
150 if (!has_0xb && !parse_8000_0008(tscan))
153 /* Prefer leaf 0x8000001e if available */
154 if (parse_8000_001e(tscan, has_0xb))
157 /* Try the NODEID MSR */
158 if (parse_fam10h_node_id(tscan))
161 legacy_set_llc(tscan);
164 void cpu_parse_topology_amd(struct topo_scan *tscan)
166 tscan->amd_nodes_per_pkg = 1;
167 parse_topology_amd(tscan);
169 if (tscan->amd_nodes_per_pkg > 1)
170 set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
173 void cpu_topology_fixup_amd(struct topo_scan *tscan)
175 struct cpuinfo_x86 *c = tscan->c;
178 * Adjust the core_id relative to the node when there is more than
181 if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1)
182 c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg;