Branch data Line data Source code
1 : : // SPDX-License-Identifier: GPL-2.0
2 : : /*
3 : : * Check for extended topology enumeration cpuid leaf 0xb and if it
4 : : * exists, use it for populating initial_apicid and cpu topology
5 : : * detection.
6 : : */
7 : :
8 : : #include <linux/cpu.h>
9 : : #include <asm/apic.h>
10 : : #include <asm/memtype.h>
11 : : #include <asm/processor.h>
12 : :
13 : : #include "cpu.h"
14 : :
15 : : /* leaf 0xb SMT level */
16 : : #define SMT_LEVEL 0
17 : :
18 : : /* extended topology sub-leaf types */
19 : : #define INVALID_TYPE 0
20 : : #define SMT_TYPE 1
21 : : #define CORE_TYPE 2
22 : : #define DIE_TYPE 5
23 : :
24 : : #define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
25 : : #define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
26 : : #define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
27 : :
28 : : #ifdef CONFIG_SMP
29 : : unsigned int __max_die_per_package __read_mostly = 1;
30 : : EXPORT_SYMBOL(__max_die_per_package);
31 : :
32 : : /*
33 : : * Check if given CPUID extended toplogy "leaf" is implemented
34 : : */
35 : : static int check_extended_topology_leaf(int leaf)
36 : : {
37 : : unsigned int eax, ebx, ecx, edx;
38 : :
39 : : cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
40 : :
41 : : if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
42 : : return -1;
43 : :
44 : : return 0;
45 : : }
46 : : /*
47 : : * Return best CPUID Extended Toplogy Leaf supported
48 : : */
49 : : static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
50 : : {
51 : : if (c->cpuid_level >= 0x1f) {
52 : : if (check_extended_topology_leaf(0x1f) == 0)
53 : : return 0x1f;
54 : : }
55 : :
56 : : if (c->cpuid_level >= 0xb) {
57 : : if (check_extended_topology_leaf(0xb) == 0)
58 : : return 0xb;
59 : : }
60 : :
61 : : return -1;
62 : : }
63 : : #endif
64 : :
65 : 0 : int detect_extended_topology_early(struct cpuinfo_x86 *c)
66 : : {
67 : : #ifdef CONFIG_SMP
68 : 0 : unsigned int eax, ebx, ecx, edx;
69 : 0 : int leaf;
70 : :
71 : 0 : leaf = detect_extended_topology_leaf(c);
72 [ # # ]: 0 : if (leaf < 0)
73 : : return -1;
74 : :
75 : 0 : set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
76 : :
77 : 0 : cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
78 : : /*
79 : : * initial apic id, which also represents 32-bit extended x2apic id.
80 : : */
81 : 0 : c->initial_apicid = edx;
82 : 0 : smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
83 : : #endif
84 : 0 : return 0;
85 : : }
86 : :
87 : : /*
88 : : * Check for extended topology enumeration cpuid leaf, and if it
89 : : * exists, use it for populating initial_apicid and cpu topology
90 : : * detection.
91 : : */
92 : 0 : int detect_extended_topology(struct cpuinfo_x86 *c)
93 : : {
94 : : #ifdef CONFIG_SMP
95 : 0 : unsigned int eax, ebx, ecx, edx, sub_index;
96 : 0 : unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
97 : 0 : unsigned int core_select_mask, core_level_siblings;
98 : 0 : unsigned int die_select_mask, die_level_siblings;
99 : 0 : int leaf;
100 : :
101 : 0 : leaf = detect_extended_topology_leaf(c);
102 [ # # ]: 0 : if (leaf < 0)
103 : : return -1;
104 : :
105 : : /*
106 : : * Populate HT related information from sub-leaf level 0.
107 : : */
108 : 0 : cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
109 : 0 : c->initial_apicid = edx;
110 : 0 : core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
111 : 0 : core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
112 : 0 : die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
113 : 0 : die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
114 : :
115 : 0 : sub_index = 1;
116 : 0 : do {
117 : 0 : cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
118 : :
119 : : /*
120 : : * Check for the Core type in the implemented sub leaves.
121 : : */
122 [ # # ]: 0 : if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
123 : 0 : core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
124 : 0 : core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
125 : 0 : die_level_siblings = core_level_siblings;
126 : 0 : die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
127 : : }
128 [ # # ]: 0 : if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
129 : 0 : die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
130 : 0 : die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
131 : : }
132 : :
133 : 0 : sub_index++;
134 [ # # ]: 0 : } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
135 : :
136 : 0 : core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
137 : 0 : die_select_mask = (~(-1 << die_plus_mask_width)) >>
138 : : core_plus_mask_width;
139 : :
140 : 0 : c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
141 : 0 : ht_mask_width) & core_select_mask;
142 : 0 : c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
143 : 0 : core_plus_mask_width) & die_select_mask;
144 : 0 : c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
145 : : die_plus_mask_width);
146 : : /*
147 : : * Reinit the apicid, now that we have extended initial_apicid.
148 : : */
149 : 0 : c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
150 : :
151 : 0 : c->x86_max_cores = (core_level_siblings / smp_num_siblings);
152 : 0 : __max_die_per_package = (die_level_siblings / core_level_siblings);
153 : : #endif
154 : 0 : return 0;
155 : : }
|