0001
0002
0003
0004
0005
0006
0007
0008 #include <linux/cpu.h>
0009 #include <asm/apic.h>
0010 #include <asm/memtype.h>
0011 #include <asm/processor.h>
0012
0013 #include "cpu.h"
0014
0015
0016 #define SMT_LEVEL 0
0017
0018
0019 #define INVALID_TYPE 0
0020 #define SMT_TYPE 1
0021 #define CORE_TYPE 2
0022 #define DIE_TYPE 5
0023
0024 #define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff)
0025 #define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f)
0026 #define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff)
0027
0028 unsigned int __max_die_per_package __read_mostly = 1;
0029 EXPORT_SYMBOL(__max_die_per_package);
0030
0031 #ifdef CONFIG_SMP
0032
0033
0034
0035 static int check_extended_topology_leaf(int leaf)
0036 {
0037 unsigned int eax, ebx, ecx, edx;
0038
0039 cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0040
0041 if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE))
0042 return -1;
0043
0044 return 0;
0045 }
0046
0047
0048
0049 static int detect_extended_topology_leaf(struct cpuinfo_x86 *c)
0050 {
0051 if (c->cpuid_level >= 0x1f) {
0052 if (check_extended_topology_leaf(0x1f) == 0)
0053 return 0x1f;
0054 }
0055
0056 if (c->cpuid_level >= 0xb) {
0057 if (check_extended_topology_leaf(0xb) == 0)
0058 return 0xb;
0059 }
0060
0061 return -1;
0062 }
0063 #endif
0064
0065 int detect_extended_topology_early(struct cpuinfo_x86 *c)
0066 {
0067 #ifdef CONFIG_SMP
0068 unsigned int eax, ebx, ecx, edx;
0069 int leaf;
0070
0071 leaf = detect_extended_topology_leaf(c);
0072 if (leaf < 0)
0073 return -1;
0074
0075 set_cpu_cap(c, X86_FEATURE_XTOPOLOGY);
0076
0077 cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0078
0079
0080
0081 c->initial_apicid = edx;
0082 smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
0083 #endif
0084 return 0;
0085 }
0086
0087
0088
0089
0090
0091
0092 int detect_extended_topology(struct cpuinfo_x86 *c)
0093 {
0094 #ifdef CONFIG_SMP
0095 unsigned int eax, ebx, ecx, edx, sub_index;
0096 unsigned int ht_mask_width, core_plus_mask_width, die_plus_mask_width;
0097 unsigned int core_select_mask, core_level_siblings;
0098 unsigned int die_select_mask, die_level_siblings;
0099 bool die_level_present = false;
0100 int leaf;
0101
0102 leaf = detect_extended_topology_leaf(c);
0103 if (leaf < 0)
0104 return -1;
0105
0106
0107
0108
0109 cpuid_count(leaf, SMT_LEVEL, &eax, &ebx, &ecx, &edx);
0110 c->initial_apicid = edx;
0111 core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx);
0112 core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0113 die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0114 die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0115
0116 sub_index = 1;
0117 do {
0118 cpuid_count(leaf, sub_index, &eax, &ebx, &ecx, &edx);
0119
0120
0121
0122
0123 if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) {
0124 core_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0125 core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0126 die_level_siblings = core_level_siblings;
0127 die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0128 }
0129 if (LEAFB_SUBTYPE(ecx) == DIE_TYPE) {
0130 die_level_present = true;
0131 die_level_siblings = LEVEL_MAX_SIBLINGS(ebx);
0132 die_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax);
0133 }
0134
0135 sub_index++;
0136 } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE);
0137
0138 core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width;
0139 die_select_mask = (~(-1 << die_plus_mask_width)) >>
0140 core_plus_mask_width;
0141
0142 c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid,
0143 ht_mask_width) & core_select_mask;
0144
0145 if (die_level_present) {
0146 c->cpu_die_id = apic->phys_pkg_id(c->initial_apicid,
0147 core_plus_mask_width) & die_select_mask;
0148 }
0149
0150 c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid,
0151 die_plus_mask_width);
0152
0153
0154
0155 c->apicid = apic->phys_pkg_id(c->initial_apicid, 0);
0156
0157 c->x86_max_cores = (core_level_siblings / smp_num_siblings);
0158 __max_die_per_package = (die_level_siblings / core_level_siblings);
0159 #endif
0160 return 0;
0161 }