aboutsummaryrefslogtreecommitdiffstats
path: root/arch/i386
diff options
context:
space:
mode:
authorAndi Kleen <ak@suse.de>2007-07-21 11:10:03 -0400
committerLinus Torvalds <torvalds@woody.linux-foundation.org>2007-07-21 21:37:08 -0400
commit67cddd947992b02f01ad093ec814738c5827d17c (patch)
tree5c10c3a1f645c119e0cc23ecdfc7c3c4dd7eacad /arch/i386
parent2aae950b21e4bc789d1fc6668faf67e8748300b7 (diff)
i386: Add L3 cache support to AMD CPUID4 emulation
With that an L3 cache is correctly reported in the cache information in /sys With fixes from Andreas Herrmann and Dean Gaudet and Joachim Deguara Signed-off-by: Andi Kleen <ak@suse.de> Signed-off-by: Linus Torvalds <torvalds@linux-foundation.org>
Diffstat (limited to 'arch/i386')
-rw-r--r--arch/i386/kernel/cpu/amd.c8
-rw-r--r--arch/i386/kernel/cpu/intel_cacheinfo.c74
2 files changed, 60 insertions, 22 deletions
diff --git a/arch/i386/kernel/cpu/amd.c b/arch/i386/kernel/cpu/amd.c
index 6f47eeeb93ea..815a5f0aa474 100644
--- a/arch/i386/kernel/cpu/amd.c
+++ b/arch/i386/kernel/cpu/amd.c
@@ -272,8 +272,12 @@ static void __cpuinit init_amd(struct cpuinfo_x86 *c)
272 } 272 }
273#endif 273#endif
274 274
275 if (cpuid_eax(0x80000000) >= 0x80000006) 275 if (cpuid_eax(0x80000000) >= 0x80000006) {
276 num_cache_leaves = 3; 276 if ((c->x86 == 0x10) && (cpuid_edx(0x80000006) & 0xf000))
277 num_cache_leaves = 4;
278 else
279 num_cache_leaves = 3;
280 }
277 281
278 if (amd_apic_timer_broken()) 282 if (amd_apic_timer_broken())
279 set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability); 283 set_bit(X86_FEATURE_LAPIC_TIMER_BROKEN, c->x86_capability);
diff --git a/arch/i386/kernel/cpu/intel_cacheinfo.c b/arch/i386/kernel/cpu/intel_cacheinfo.c
index 25b4b7d89cae..43db806b9609 100644
--- a/arch/i386/kernel/cpu/intel_cacheinfo.c
+++ b/arch/i386/kernel/cpu/intel_cacheinfo.c
@@ -4,7 +4,7 @@
4 * Changes: 4 * Changes:
5 * Venkatesh Pallipadi : Adding cache identification through cpuid(4) 5 * Venkatesh Pallipadi : Adding cache identification through cpuid(4)
6 * Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure. 6 * Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
7 * Andi Kleen : CPUID4 emulation on AMD. 7 * Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD.
8 */ 8 */
9 9
10#include <linux/init.h> 10#include <linux/init.h>
@@ -135,7 +135,7 @@ unsigned short num_cache_leaves;
135 135
136/* AMD doesn't have CPUID4. Emulate it here to report the same 136/* AMD doesn't have CPUID4. Emulate it here to report the same
137 information to the user. This makes some assumptions about the machine: 137 information to the user. This makes some assumptions about the machine:
138 No L3, L2 not shared, no SMT etc. that is currently true on AMD CPUs. 138 L2 not shared, no SMT etc. that is currently true on AMD CPUs.
139 139
140 In theory the TLBs could be reported as fake type (they are in "dummy"). 140 In theory the TLBs could be reported as fake type (they are in "dummy").
141 Maybe later */ 141 Maybe later */
@@ -159,13 +159,26 @@ union l2_cache {
159 unsigned val; 159 unsigned val;
160}; 160};
161 161
162union l3_cache {
163 struct {
164 unsigned line_size : 8;
165 unsigned lines_per_tag : 4;
166 unsigned assoc : 4;
167 unsigned res : 2;
168 unsigned size_encoded : 14;
169 };
170 unsigned val;
171};
172
162static const unsigned short assocs[] = { 173static const unsigned short assocs[] = {
163 [1] = 1, [2] = 2, [4] = 4, [6] = 8, 174 [1] = 1, [2] = 2, [4] = 4, [6] = 8,
164 [8] = 16, 175 [8] = 16, [0xa] = 32, [0xb] = 48,
176 [0xc] = 64,
165 [0xf] = 0xffff // ?? 177 [0xf] = 0xffff // ??
166 }; 178};
167static const unsigned char levels[] = { 1, 1, 2 }; 179
168static const unsigned char types[] = { 1, 2, 3 }; 180static const unsigned char levels[] = { 1, 1, 2, 3 };
181static const unsigned char types[] = { 1, 2, 3, 3 };
169 182
170static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, 183static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
171 union _cpuid4_leaf_ebx *ebx, 184 union _cpuid4_leaf_ebx *ebx,
@@ -175,37 +188,58 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
175 unsigned line_size, lines_per_tag, assoc, size_in_kb; 188 unsigned line_size, lines_per_tag, assoc, size_in_kb;
176 union l1_cache l1i, l1d; 189 union l1_cache l1i, l1d;
177 union l2_cache l2; 190 union l2_cache l2;
191 union l3_cache l3;
192 union l1_cache *l1 = &l1d;
178 193
179 eax->full = 0; 194 eax->full = 0;
180 ebx->full = 0; 195 ebx->full = 0;
181 ecx->full = 0; 196 ecx->full = 0;
182 197
183 cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val); 198 cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
184 cpuid(0x80000006, &dummy, &dummy, &l2.val, &dummy); 199 cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
185 200
186 if (leaf > 2 || !l1d.val || !l1i.val || !l2.val) 201 switch (leaf) {
187 return; 202 case 1:
188 203 l1 = &l1i;
189 eax->split.is_self_initializing = 1; 204 case 0:
190 eax->split.type = types[leaf]; 205 if (!l1->val)
191 eax->split.level = levels[leaf]; 206 return;
192 eax->split.num_threads_sharing = 0;
193 eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
194
195 if (leaf <= 1) {
196 union l1_cache *l1 = leaf == 0 ? &l1d : &l1i;
197 assoc = l1->assoc; 207 assoc = l1->assoc;
198 line_size = l1->line_size; 208 line_size = l1->line_size;
199 lines_per_tag = l1->lines_per_tag; 209 lines_per_tag = l1->lines_per_tag;
200 size_in_kb = l1->size_in_kb; 210 size_in_kb = l1->size_in_kb;
201 } else { 211 break;
212 case 2:
213 if (!l2.val)
214 return;
202 assoc = l2.assoc; 215 assoc = l2.assoc;
203 line_size = l2.line_size; 216 line_size = l2.line_size;
204 lines_per_tag = l2.lines_per_tag; 217 lines_per_tag = l2.lines_per_tag;
205 /* cpu_data has errata corrections for K7 applied */ 218 /* cpu_data has errata corrections for K7 applied */
206 size_in_kb = current_cpu_data.x86_cache_size; 219 size_in_kb = current_cpu_data.x86_cache_size;
220 break;
221 case 3:
222 if (!l3.val)
223 return;
224 assoc = l3.assoc;
225 line_size = l3.line_size;
226 lines_per_tag = l3.lines_per_tag;
227 size_in_kb = l3.size_encoded * 512;
228 break;
229 default:
230 return;
207 } 231 }
208 232
233 eax->split.is_self_initializing = 1;
234 eax->split.type = types[leaf];
235 eax->split.level = levels[leaf];
236 if (leaf == 3)
237 eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
238 else
239 eax->split.num_threads_sharing = 0;
240 eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
241
242
209 if (assoc == 0xf) 243 if (assoc == 0xf)
210 eax->split.is_fully_associative = 1; 244 eax->split.is_fully_associative = 1;
211 ebx->split.coherency_line_size = line_size - 1; 245 ebx->split.coherency_line_size = line_size - 1;