| .. | .. |
|---|
| 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 | } |
|---|