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