]> Git Repo - J-linux.git/blob - arch/x86/kernel/cpu/topology_amd.c
Merge tag 'vfs-6.13-rc7.fixes' of git://git.kernel.org/pub/scm/linux/kernel/git/vfs/vfs
[J-linux.git] / arch / x86 / kernel / cpu / topology_amd.c
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_topoext)
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. Only valid for family >= 0x17.
88          */
89         if (!has_topoext && tscan->c->x86 >= 0x17) {
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 void 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;
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 }
140
141 static void legacy_set_llc(struct topo_scan *tscan)
142 {
143         unsigned int apicid = tscan->c->topo.initial_apicid;
144
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];
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_topoext = false;
173
174         /*
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.
181          */
182         if (cpu_feature_enabled(X86_FEATURE_TOPOEXT))
183                 has_topoext = cpu_parse_topology_ext(tscan);
184
185         if (cpu_feature_enabled(X86_FEATURE_AMD_HETEROGENEOUS_CORES))
186                 tscan->c->topo.cpu_type = cpuid_ebx(0x80000026);
187
188         if (!has_topoext && !parse_8000_0008(tscan))
189                 return;
190
191         /* Prefer leaf 0x8000001e if available */
192         if (parse_8000_001e(tscan, has_topoext))
193                 return;
194
195         /* Try the NODEID MSR */
196         parse_fam10h_node_id(tscan);
197 }
198
199 void cpu_parse_topology_amd(struct topo_scan *tscan)
200 {
201         tscan->amd_nodes_per_pkg = 1;
202         topoext_fixup(tscan);
203         parse_topology_amd(tscan);
204         legacy_set_llc(tscan);
205
206         if (tscan->amd_nodes_per_pkg > 1)
207                 set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
208 }
209
210 void cpu_topology_fixup_amd(struct topo_scan *tscan)
211 {
212         struct cpuinfo_x86 *c = tscan->c;
213
214         /*
215          * Adjust the core_id relative to the node when there is more than
216          * one node.
217          */
218         if (tscan->c->x86 < 0x17 && tscan->amd_nodes_per_pkg > 1)
219                 c->topo.core_id %= tscan->dom_ncpus[TOPO_CORE_DOMAIN] / tscan->amd_nodes_per_pkg;
220 }
This page took 0.039175 seconds and 4 git commands to generate.