~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

TOMOYO Linux Cross Reference
Linux/arch/x86/kernel/cpu/topology_amd.c

Version: ~ [ linux-6.11-rc3 ] ~ [ linux-6.10.4 ] ~ [ linux-6.9.12 ] ~ [ linux-6.8.12 ] ~ [ linux-6.7.12 ] ~ [ linux-6.6.45 ] ~ [ linux-6.5.13 ] ~ [ linux-6.4.16 ] ~ [ linux-6.3.13 ] ~ [ linux-6.2.16 ] ~ [ linux-6.1.104 ] ~ [ linux-6.0.19 ] ~ [ linux-5.19.17 ] ~ [ linux-5.18.19 ] ~ [ linux-5.17.15 ] ~ [ linux-5.16.20 ] ~ [ linux-5.15.164 ] ~ [ linux-5.14.21 ] ~ [ linux-5.13.19 ] ~ [ linux-5.12.19 ] ~ [ linux-5.11.22 ] ~ [ linux-5.10.223 ] ~ [ linux-5.9.16 ] ~ [ linux-5.8.18 ] ~ [ linux-5.7.19 ] ~ [ linux-5.6.19 ] ~ [ linux-5.5.19 ] ~ [ linux-5.4.281 ] ~ [ linux-5.3.18 ] ~ [ linux-5.2.21 ] ~ [ linux-5.1.21 ] ~ [ linux-5.0.21 ] ~ [ linux-4.20.17 ] ~ [ linux-4.19.319 ] ~ [ linux-4.18.20 ] ~ [ linux-4.17.19 ] ~ [ linux-4.16.18 ] ~ [ linux-4.15.18 ] ~ [ linux-4.14.336 ] ~ [ linux-4.13.16 ] ~ [ linux-4.12.14 ] ~ [ linux-4.11.12 ] ~ [ linux-4.10.17 ] ~ [ linux-4.9.337 ] ~ [ linux-4.4.302 ] ~ [ linux-3.10.108 ] ~ [ linux-2.6.32.71 ] ~ [ linux-2.6.0 ] ~ [ linux-2.4.37.11 ] ~ [ unix-v6-master ] ~ [ ccs-tools-1.8.9 ] ~ [ policy-sample ] ~
Architecture: ~ [ i386 ] ~ [ alpha ] ~ [ m68k ] ~ [ mips ] ~ [ ppc ] ~ [ sparc ] ~ [ sparc64 ] ~

  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 (!has_topoext && !parse_8000_0008(tscan))
186                 return;
187 
188         /* Prefer leaf 0x8000001e if available */
189         if (parse_8000_001e(tscan, has_topoext))
190                 return;
191 
192         /* Try the NODEID MSR */
193         parse_fam10h_node_id(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         legacy_set_llc(tscan);
202 
203         if (tscan->amd_nodes_per_pkg > 1)
204                 set_cpu_cap(tscan->c, X86_FEATURE_AMD_DCM);
205 }
206 
207 void cpu_topology_fixup_amd(struct topo_scan *tscan)
208 {
209         struct cpuinfo_x86 *c = tscan->c;
210 
211         /*
212          * Adjust the core_id relative to the node when there is more than
213          * one node.
214          */
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;
217 }
218 

~ [ source navigation ] ~ [ diff markup ] ~ [ identifier search ] ~

kernel.org | git.kernel.org | LWN.net | Project Home | SVN repository | Mail admin

Linux® is a registered trademark of Linus Torvalds in the United States and other countries.
TOMOYO® is a registered trademark of NTT DATA CORPORATION.

sflogo.php