xref: /openbmc/linux/arch/x86/kernel/cpu/topology.c (revision 78700c0a)
1 /*
2  * Check for extended topology enumeration cpuid leaf 0xb and if it
3  * exists, use it for populating initial_apicid and cpu topology
4  * detection.
5  */
6 
7 #include <linux/cpu.h>
8 #include <asm/apic.h>
9 #include <asm/pat.h>
10 #include <asm/processor.h>
11 
12 /* leaf 0xb SMT level */
13 #define SMT_LEVEL	0
14 
15 /* leaf 0xb sub-leaf types */
16 #define INVALID_TYPE	0
17 #define SMT_TYPE	1
18 #define CORE_TYPE	2
19 
20 #define LEAFB_SUBTYPE(ecx)		(((ecx) >> 8) & 0xff)
21 #define BITS_SHIFT_NEXT_LEVEL(eax)	((eax) & 0x1f)
22 #define LEVEL_MAX_SIBLINGS(ebx)		((ebx) & 0xffff)
23 
24 /*
25  * Check for extended topology enumeration cpuid leaf 0xb and if it
26  * exists, use it for populating initial_apicid and cpu topology
27  * detection.
28  */
29 void detect_extended_topology(struct cpuinfo_x86 *c)
30 {
31 #ifdef CONFIG_SMP
32 	unsigned int eax, ebx, ecx, edx, sub_index;
33 	unsigned int ht_mask_width, core_plus_mask_width;
34 	unsigned int core_select_mask, core_level_siblings;
35 	static bool printed;
36 
37 	if (c->cpuid_level < 0xb)
38 		return;
39 
40 	cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
41 
42 	/*
43 	 * check if the cpuid leaf 0xb is actually implemented.
44 	 */
45 	if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
46 		return;
47 
48 	set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
49 
50 	/*
51 	 * initial apic id, which also represents 32-bit extended x2apic id.
52 	 */
53 	c->initial_apicid = edx;
54 
55 	/*
56 	 * Populate HT related information from sub-leaf level 0.
57 	 */
58 	core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
59 	core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
60 
61 	sub_index = 1;
62 	do {
63 		cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
64 
65 		/*
66 		 * Check for the Core type in the implemented sub leaves.
67 		 */
68 		if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
69 			core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
70 			core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
71 			break;
72 		}
73 
74 		sub_index++;
75 	} while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
76 
77 	core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
78 
79 	c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
80 						 & core_select_mask;
81 	c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
82 	/*
83 	 * Reinit the apicid, now that we have extended initial_apicid.
84 	 */
85 	c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
86 
87 	c->x86_max_cores = (core_level_siblings / smp_num_siblings);
88 
89 	if (!printed) {
90 		pr_info("CPU: Physical Processor ID: %d\n",
91 		       c->phys_proc_id);
92 		if (c->x86_max_cores > 1)
93 			pr_info("CPU: Processor Core ID: %d\n",
94 			       c->cpu_core_id);
95 		printed = 1;
96 	}
97 	return;
98 #endif
99 }
100