Book a Demo!
CoCalc Logo Icon
StoreFeaturesDocsShareSupportNewsAboutPoliciesSign UpSign In
torvalds
GitHub Repository: torvalds/linux
Path: blob/master/arch/x86/kernel/cpu/topology_common.c
50333 views
1
// SPDX-License-Identifier: GPL-2.0
2
#include <linux/cpu.h>
3
4
#include <xen/xen.h>
5
6
#include <asm/intel-family.h>
7
#include <asm/apic.h>
8
#include <asm/processor.h>
9
#include <asm/smp.h>
10
11
#include "cpu.h"
12
13
struct x86_topology_system x86_topo_system __ro_after_init;
14
EXPORT_SYMBOL_GPL(x86_topo_system);
15
16
unsigned int __amd_nodes_per_pkg __ro_after_init;
17
EXPORT_SYMBOL_GPL(__amd_nodes_per_pkg);
18
19
/* CPUs which are the primary SMT threads */
20
struct cpumask __cpu_primary_thread_mask __read_mostly;
21
22
void topology_set_dom(struct topo_scan *tscan, enum x86_topology_domains dom,
23
unsigned int shift, unsigned int ncpus)
24
{
25
topology_update_dom(tscan, dom, shift, ncpus);
26
27
/* Propagate to the upper levels */
28
for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {
29
tscan->dom_shifts[dom] = tscan->dom_shifts[dom - 1];
30
tscan->dom_ncpus[dom] = tscan->dom_ncpus[dom - 1];
31
}
32
}
33
34
enum x86_topology_cpu_type get_topology_cpu_type(struct cpuinfo_x86 *c)
35
{
36
if (c->x86_vendor == X86_VENDOR_INTEL) {
37
switch (c->topo.intel_type) {
38
case INTEL_CPU_TYPE_ATOM: return TOPO_CPU_TYPE_EFFICIENCY;
39
case INTEL_CPU_TYPE_CORE: return TOPO_CPU_TYPE_PERFORMANCE;
40
}
41
}
42
if (c->x86_vendor == X86_VENDOR_AMD) {
43
switch (c->topo.amd_type) {
44
case 0: return TOPO_CPU_TYPE_PERFORMANCE;
45
case 1: return TOPO_CPU_TYPE_EFFICIENCY;
46
}
47
}
48
49
return TOPO_CPU_TYPE_UNKNOWN;
50
}
51
52
const char *get_topology_cpu_type_name(struct cpuinfo_x86 *c)
53
{
54
switch (get_topology_cpu_type(c)) {
55
case TOPO_CPU_TYPE_PERFORMANCE:
56
return "performance";
57
case TOPO_CPU_TYPE_EFFICIENCY:
58
return "efficiency";
59
default:
60
return "unknown";
61
}
62
}
63
64
static unsigned int __maybe_unused parse_num_cores_legacy(struct cpuinfo_x86 *c)
65
{
66
struct {
67
u32 cache_type : 5,
68
unused : 21,
69
ncores : 6;
70
} eax;
71
72
if (c->cpuid_level < 4)
73
return 1;
74
75
cpuid_subleaf_reg(4, 0, CPUID_EAX, &eax);
76
if (!eax.cache_type)
77
return 1;
78
79
return eax.ncores + 1;
80
}
81
82
static void parse_legacy(struct topo_scan *tscan)
83
{
84
unsigned int cores, core_shift, smt_shift = 0;
85
struct cpuinfo_x86 *c = tscan->c;
86
87
cores = parse_num_cores_legacy(c);
88
core_shift = get_count_order(cores);
89
90
if (cpu_has(c, X86_FEATURE_HT)) {
91
if (!WARN_ON_ONCE(tscan->ebx1_nproc_shift < core_shift))
92
smt_shift = tscan->ebx1_nproc_shift - core_shift;
93
/*
94
* The parser expects leaf 0xb/0x1f format, which means
95
* the number of logical processors at core level is
96
* counting threads.
97
*/
98
core_shift += smt_shift;
99
cores <<= smt_shift;
100
}
101
102
topology_set_dom(tscan, TOPO_SMT_DOMAIN, smt_shift, 1U << smt_shift);
103
topology_set_dom(tscan, TOPO_CORE_DOMAIN, core_shift, cores);
104
}
105
106
static bool fake_topology(struct topo_scan *tscan)
107
{
108
/*
109
* Preset the CORE level shift for CPUID less systems and XEN_PV,
110
* which has useless CPUID information.
111
*/
112
topology_set_dom(tscan, TOPO_SMT_DOMAIN, 0, 1);
113
topology_set_dom(tscan, TOPO_CORE_DOMAIN, 0, 1);
114
115
return tscan->c->cpuid_level < 1;
116
}
117
118
static void parse_topology(struct topo_scan *tscan, bool early)
119
{
120
const struct cpuinfo_topology topo_defaults = {
121
.cu_id = 0xff,
122
.llc_id = BAD_APICID,
123
.l2c_id = BAD_APICID,
124
.cpu_type = TOPO_CPU_TYPE_UNKNOWN,
125
};
126
struct cpuinfo_x86 *c = tscan->c;
127
struct {
128
u32 unused0 : 16,
129
nproc : 8,
130
apicid : 8;
131
} ebx;
132
133
c->topo = topo_defaults;
134
135
if (fake_topology(tscan))
136
return;
137
138
/* Preset Initial APIC ID from CPUID leaf 1 */
139
cpuid_leaf_reg(1, CPUID_EBX, &ebx);
140
c->topo.initial_apicid = ebx.apicid;
141
142
/*
143
* The initial invocation from early_identify_cpu() happens before
144
* the APIC is mapped or X2APIC enabled. For establishing the
145
* topology, that's not required. Use the initial APIC ID.
146
*/
147
if (early)
148
c->topo.apicid = c->topo.initial_apicid;
149
else
150
c->topo.apicid = read_apic_id();
151
152
/* The above is sufficient for UP */
153
if (!IS_ENABLED(CONFIG_SMP))
154
return;
155
156
tscan->ebx1_nproc_shift = get_count_order(ebx.nproc);
157
158
switch (c->x86_vendor) {
159
case X86_VENDOR_AMD:
160
if (IS_ENABLED(CONFIG_CPU_SUP_AMD))
161
cpu_parse_topology_amd(tscan);
162
break;
163
case X86_VENDOR_CENTAUR:
164
case X86_VENDOR_ZHAOXIN:
165
parse_legacy(tscan);
166
break;
167
case X86_VENDOR_INTEL:
168
if (!IS_ENABLED(CONFIG_CPU_SUP_INTEL) || !cpu_parse_topology_ext(tscan))
169
parse_legacy(tscan);
170
if (c->cpuid_level >= 0x1a)
171
c->topo.cpu_type = cpuid_eax(0x1a);
172
break;
173
case X86_VENDOR_HYGON:
174
if (IS_ENABLED(CONFIG_CPU_SUP_HYGON))
175
cpu_parse_topology_amd(tscan);
176
break;
177
}
178
}
179
180
static void topo_set_ids(struct topo_scan *tscan, bool early)
181
{
182
struct cpuinfo_x86 *c = tscan->c;
183
u32 apicid = c->topo.apicid;
184
185
c->topo.pkg_id = topo_shift_apicid(apicid, TOPO_PKG_DOMAIN);
186
c->topo.die_id = topo_shift_apicid(apicid, TOPO_DIE_DOMAIN);
187
188
if (!early) {
189
c->topo.logical_pkg_id = topology_get_logical_id(apicid, TOPO_PKG_DOMAIN);
190
c->topo.logical_die_id = topology_get_logical_id(apicid, TOPO_DIE_DOMAIN);
191
c->topo.logical_core_id = topology_get_logical_id(apicid, TOPO_CORE_DOMAIN);
192
}
193
194
/* Package relative core ID */
195
c->topo.core_id = (apicid & topo_domain_mask(TOPO_PKG_DOMAIN)) >>
196
x86_topo_system.dom_shifts[TOPO_SMT_DOMAIN];
197
198
c->topo.amd_node_id = tscan->amd_node_id;
199
200
if (c->x86_vendor == X86_VENDOR_AMD)
201
cpu_topology_fixup_amd(tscan);
202
}
203
204
void cpu_parse_topology(struct cpuinfo_x86 *c)
205
{
206
unsigned int dom, cpu = smp_processor_id();
207
struct topo_scan tscan = { .c = c, };
208
209
parse_topology(&tscan, false);
210
211
if (IS_ENABLED(CONFIG_X86_LOCAL_APIC)) {
212
if (c->topo.initial_apicid != c->topo.apicid) {
213
pr_err(FW_BUG "CPU%4u: APIC ID mismatch. CPUID: 0x%04x APIC: 0x%04x\n",
214
cpu, c->topo.initial_apicid, c->topo.apicid);
215
}
216
217
if (c->topo.apicid != cpuid_to_apicid[cpu]) {
218
pr_err(FW_BUG "CPU%4u: APIC ID mismatch. Firmware: 0x%04x APIC: 0x%04x\n",
219
cpu, cpuid_to_apicid[cpu], c->topo.apicid);
220
}
221
}
222
223
for (dom = TOPO_SMT_DOMAIN; dom < TOPO_MAX_DOMAIN; dom++) {
224
if (tscan.dom_shifts[dom] == x86_topo_system.dom_shifts[dom])
225
continue;
226
pr_err(FW_BUG "CPU%d: Topology domain %u shift %u != %u\n", cpu, dom,
227
tscan.dom_shifts[dom], x86_topo_system.dom_shifts[dom]);
228
}
229
230
topo_set_ids(&tscan, false);
231
}
232
233
void __init cpu_init_topology(struct cpuinfo_x86 *c)
234
{
235
struct topo_scan tscan = { .c = c, };
236
unsigned int dom, sft;
237
238
parse_topology(&tscan, true);
239
240
/* Copy the shift values and calculate the unit sizes. */
241
memcpy(x86_topo_system.dom_shifts, tscan.dom_shifts, sizeof(x86_topo_system.dom_shifts));
242
243
dom = TOPO_SMT_DOMAIN;
244
x86_topo_system.dom_size[dom] = 1U << x86_topo_system.dom_shifts[dom];
245
246
for (dom++; dom < TOPO_MAX_DOMAIN; dom++) {
247
sft = x86_topo_system.dom_shifts[dom] - x86_topo_system.dom_shifts[dom - 1];
248
x86_topo_system.dom_size[dom] = 1U << sft;
249
}
250
251
topo_set_ids(&tscan, true);
252
253
/*
254
* AMD systems have Nodes per package which cannot be mapped to
255
* APIC ID.
256
*/
257
__amd_nodes_per_pkg = tscan.amd_nodes_per_pkg;
258
}
259
260