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