Commit | Line | Data |
---|---|---|
1d67953f VP |
1 | /* |
2 | * Routines to indentify additional cpu features that are scattered in | |
3 | * cpuid space. | |
4 | */ | |
1d67953f VP |
5 | #include <linux/cpu.h> |
6 | ||
8d4a4300 | 7 | #include <asm/pat.h> |
1d67953f VP |
8 | #include <asm/processor.h> |
9 | ||
7b6aa335 | 10 | #include <asm/apic.h> |
bbb65d2d | 11 | |
1d67953f VP |
12 | struct cpuid_bit { |
13 | u16 feature; | |
14 | u8 reg; | |
15 | u8 bit; | |
16 | u32 level; | |
17 | }; | |
18 | ||
19 | enum cpuid_regs { | |
20 | CR_EAX = 0, | |
21 | CR_ECX, | |
22 | CR_EDX, | |
23 | CR_EBX | |
24 | }; | |
25 | ||
26 | void __cpuinit init_scattered_cpuid_features(struct cpuinfo_x86 *c) | |
27 | { | |
28 | u32 max_level; | |
29 | u32 regs[4]; | |
30 | const struct cpuid_bit *cb; | |
31 | ||
02dde8b4 | 32 | static const struct cpuid_bit __cpuinitconst cpuid_bits[] = { |
1d67953f | 33 | { X86_FEATURE_IDA, CR_EAX, 1, 0x00000006 }, |
db954b58 | 34 | { X86_FEATURE_ARAT, CR_EAX, 2, 0x00000006 }, |
1d67953f VP |
35 | { 0, 0, 0, 0 } |
36 | }; | |
37 | ||
38 | for (cb = cpuid_bits; cb->feature; cb++) { | |
39 | ||
40 | /* Verify that the level is valid */ | |
41 | max_level = cpuid_eax(cb->level & 0xffff0000); | |
42 | if (max_level < cb->level || | |
43 | max_level > (cb->level | 0xffff)) | |
44 | continue; | |
45 | ||
46 | cpuid(cb->level, ®s[CR_EAX], ®s[CR_EBX], | |
47 | ®s[CR_ECX], ®s[CR_EDX]); | |
48 | ||
49 | if (regs[cb->reg] & (1 << cb->bit)) | |
53756d37 | 50 | set_cpu_cap(c, cb->feature); |
1d67953f VP |
51 | } |
52 | } | |
8d4a4300 | 53 | |
bbb65d2d SS |
54 | /* leaf 0xb SMT level */ |
55 | #define SMT_LEVEL 0 | |
56 | ||
57 | /* leaf 0xb sub-leaf types */ | |
58 | #define INVALID_TYPE 0 | |
59 | #define SMT_TYPE 1 | |
60 | #define CORE_TYPE 2 | |
61 | ||
62 | #define LEAFB_SUBTYPE(ecx) (((ecx) >> 8) & 0xff) | |
63 | #define BITS_SHIFT_NEXT_LEVEL(eax) ((eax) & 0x1f) | |
64 | #define LEVEL_MAX_SIBLINGS(ebx) ((ebx) & 0xffff) | |
65 | ||
66 | /* | |
67 | * Check for extended topology enumeration cpuid leaf 0xb and if it | |
68 | * exists, use it for populating initial_apicid and cpu topology | |
69 | * detection. | |
70 | */ | |
71 | void __cpuinit detect_extended_topology(struct cpuinfo_x86 *c) | |
72 | { | |
3e5095d1 | 73 | #ifdef CONFIG_SMP |
bbb65d2d SS |
74 | unsigned int eax, ebx, ecx, edx, sub_index; |
75 | unsigned int ht_mask_width, core_plus_mask_width; | |
76 | unsigned int core_select_mask, core_level_siblings; | |
77 | ||
78 | if (c->cpuid_level < 0xb) | |
79 | return; | |
80 | ||
81 | cpuid_count(0xb, SMT_LEVEL, &eax, &ebx, &ecx, &edx); | |
82 | ||
83 | /* | |
84 | * check if the cpuid leaf 0xb is actually implemented. | |
85 | */ | |
86 | if (ebx == 0 || (LEAFB_SUBTYPE(ecx) != SMT_TYPE)) | |
87 | return; | |
88 | ||
89 | set_cpu_cap(c, X86_FEATURE_XTOPOLOGY); | |
90 | ||
91 | /* | |
92 | * initial apic id, which also represents 32-bit extended x2apic id. | |
93 | */ | |
94 | c->initial_apicid = edx; | |
95 | ||
96 | /* | |
97 | * Populate HT related information from sub-leaf level 0. | |
98 | */ | |
99 | core_level_siblings = smp_num_siblings = LEVEL_MAX_SIBLINGS(ebx); | |
100 | core_plus_mask_width = ht_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); | |
101 | ||
102 | sub_index = 1; | |
103 | do { | |
104 | cpuid_count(0xb, sub_index, &eax, &ebx, &ecx, &edx); | |
105 | ||
106 | /* | |
107 | * Check for the Core type in the implemented sub leaves. | |
108 | */ | |
109 | if (LEAFB_SUBTYPE(ecx) == CORE_TYPE) { | |
110 | core_level_siblings = LEVEL_MAX_SIBLINGS(ebx); | |
111 | core_plus_mask_width = BITS_SHIFT_NEXT_LEVEL(eax); | |
112 | break; | |
113 | } | |
114 | ||
115 | sub_index++; | |
116 | } while (LEAFB_SUBTYPE(ecx) != INVALID_TYPE); | |
117 | ||
118 | core_select_mask = (~(-1 << core_plus_mask_width)) >> ht_mask_width; | |
119 | ||
cb8cc442 | 120 | c->cpu_core_id = apic->phys_pkg_id(c->initial_apicid, ht_mask_width) |
bbb65d2d | 121 | & core_select_mask; |
cb8cc442 | 122 | c->phys_proc_id = apic->phys_pkg_id(c->initial_apicid, core_plus_mask_width); |
345077cd SS |
123 | /* |
124 | * Reinit the apicid, now that we have extended initial_apicid. | |
125 | */ | |
cb8cc442 | 126 | c->apicid = apic->phys_pkg_id(c->initial_apicid, 0); |
d4c9a9f3 | 127 | |
bbb65d2d SS |
128 | c->x86_max_cores = (core_level_siblings / smp_num_siblings); |
129 | ||
130 | ||
131 | printk(KERN_INFO "CPU: Physical Processor ID: %d\n", | |
132 | c->phys_proc_id); | |
133 | if (c->x86_max_cores > 1) | |
134 | printk(KERN_INFO "CPU: Processor Core ID: %d\n", | |
135 | c->cpu_core_id); | |
136 | return; | |
11c231a9 | 137 | #endif |
bbb65d2d | 138 | } |