GNU Linux-libre 4.9.304-gnu1
[releases.git] / arch / x86 / kernel / cpu / topology.c
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 int detect_extended_topology_early(struct cpuinfo_x86 *c)
30 {
31 #ifdef CONFIG_SMP
32         unsigned int eax, ebx, ecx, edx;
33
34         if (c->cpuid_level < 0xb)
35                 return -1;
36
37         cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
38
39         /*
40          * check if the cpuid leaf 0xb is actually implemented.
41          */
42         if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
43                 return -1;
44
45         set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
46
47         /*
48          * initial apic id, which also represents 32-bit extended x2apic id.
49          */
50         c->initial_apicid = edx;
51         smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
52 #endif
53         return 0;
54 }
55
56 /*
57  * Check for extended topology enumeration cpuid leaf 0xb and if it
58  * exists, use it for populating initial_apicid and cpu topology
59  * detection.
60  */
61 void detect_extended_topology(struct cpuinfo_x86 *c)
62 {
63 #ifdef CONFIG_SMP
64         unsigned int eax, ebx, ecx, edx, sub_index;
65         unsigned int ht_mask_width, core_plus_mask_width;
66         unsigned int core_select_mask, core_level_siblings;
67
68         if (detect_extended_topology_early(c) < 0)
69                 return;
70
71         /*
72          * Populate HT related information from sub-leaf level 0.
73          */
74         cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
75         core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
76         core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
77
78         sub_index = 1;
79         do {
80                 cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx);
81
82                 /*
83                  * Check for the Core type in the implemented sub leaves.
84                  */
85                 if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
86                         core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
87                         core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
88                         break;
89                 }
90
91                 sub_index++;
92         } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
93
94         core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
95
96         c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width)
97                                                  & core_select_mask;
98         c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width);
99         /*
100          * Reinit the apicid, now that we have extended initial_apicid.
101          */
102         c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
103
104         c->x86_max_cores = (core_level_siblings / smp_num_siblings);
105 #endif
106 }