ia64/xen-unstable

view xen/arch/x86/cpu/intel_cacheinfo.c @ 19835:edfdeb150f27

Fix buildsystem to detect udev > version 124

udev removed the udevinfo symlink from versions higher than 123 and
xen's build-system could not detect if udev is in place and has the
required version.

Signed-off-by: Marc-A. Dahlhaus <mad@wol.de>
author Keir Fraser <keir.fraser@citrix.com>
date Thu Jun 25 13:02:37 2009 +0100 (2009-06-25)
parents f1947dddb5a0
children
line source
1 /*
2 * Routines to indentify caches on Intel CPU.
3 *
4 * Changes:
5 * Venkatesh Pallipadi : Adding cache identification through cpuid(4)
6 * Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
7 * Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD.
8 */
10 #include <xen/config.h>
11 #include <xen/init.h>
12 #include <xen/lib.h>
13 #include <xen/errno.h>
14 #include <asm/processor.h>
16 #define LVL_1_INST 1
17 #define LVL_1_DATA 2
18 #define LVL_2 3
19 #define LVL_3 4
20 #define LVL_TRACE 5
22 struct _cache_table
23 {
24 unsigned char descriptor;
25 char cache_type;
26 short size;
27 };
29 /* all the cache descriptor types we care about (no TLB or trace cache entries) */
30 static struct _cache_table cache_table[] __cpuinitdata =
31 {
32 { 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */
33 { 0x08, LVL_1_INST, 16 }, /* 4-way set assoc, 32 byte line size */
34 { 0x0a, LVL_1_DATA, 8 }, /* 2 way set assoc, 32 byte line size */
35 { 0x0c, LVL_1_DATA, 16 }, /* 4-way set assoc, 32 byte line size */
36 { 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */
37 { 0x23, LVL_3, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */
38 { 0x25, LVL_3, 2048 }, /* 8-way set assoc, sectored cache, 64 byte line size */
39 { 0x29, LVL_3, 4096 }, /* 8-way set assoc, sectored cache, 64 byte line size */
40 { 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */
41 { 0x30, LVL_1_INST, 32 }, /* 8-way set assoc, 64 byte line size */
42 { 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */
43 { 0x3a, LVL_2, 192 }, /* 6-way set assoc, sectored cache, 64 byte line size */
44 { 0x3b, LVL_2, 128 }, /* 2-way set assoc, sectored cache, 64 byte line size */
45 { 0x3c, LVL_2, 256 }, /* 4-way set assoc, sectored cache, 64 byte line size */
46 { 0x3d, LVL_2, 384 }, /* 6-way set assoc, sectored cache, 64 byte line size */
47 { 0x3e, LVL_2, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */
48 { 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */
49 { 0x42, LVL_2, 256 }, /* 4-way set assoc, 32 byte line size */
50 { 0x43, LVL_2, 512 }, /* 4-way set assoc, 32 byte line size */
51 { 0x44, LVL_2, 1024 }, /* 4-way set assoc, 32 byte line size */
52 { 0x45, LVL_2, 2048 }, /* 4-way set assoc, 32 byte line size */
53 { 0x46, LVL_3, 4096 }, /* 4-way set assoc, 64 byte line size */
54 { 0x47, LVL_3, 8192 }, /* 8-way set assoc, 64 byte line size */
55 { 0x49, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */
56 { 0x4a, LVL_3, 6144 }, /* 12-way set assoc, 64 byte line size */
57 { 0x4b, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */
58 { 0x4c, LVL_3, 12288 }, /* 12-way set assoc, 64 byte line size */
59 { 0x4d, LVL_3, 16384 }, /* 16-way set assoc, 64 byte line size */
60 { 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */
61 { 0x66, LVL_1_DATA, 8 }, /* 4-way set assoc, sectored cache, 64 byte line size */
62 { 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */
63 { 0x68, LVL_1_DATA, 32 }, /* 4-way set assoc, sectored cache, 64 byte line size */
64 { 0x70, LVL_TRACE, 12 }, /* 8-way set assoc */
65 { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */
66 { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */
67 { 0x73, LVL_TRACE, 64 }, /* 8-way set assoc */
68 { 0x78, LVL_2, 1024 }, /* 4-way set assoc, 64 byte line size */
69 { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */
70 { 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */
71 { 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */
72 { 0x7c, LVL_2, 1024 }, /* 8-way set assoc, sectored cache, 64 byte line size */
73 { 0x7d, LVL_2, 2048 }, /* 8-way set assoc, 64 byte line size */
74 { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */
75 { 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */
76 { 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */
77 { 0x84, LVL_2, 1024 }, /* 8-way set assoc, 32 byte line size */
78 { 0x85, LVL_2, 2048 }, /* 8-way set assoc, 32 byte line size */
79 { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */
80 { 0x87, LVL_2, 1024 }, /* 8-way set assoc, 64 byte line size */
81 { 0x00, 0, 0}
82 };
85 enum _cache_type
86 {
87 CACHE_TYPE_NULL = 0,
88 CACHE_TYPE_DATA = 1,
89 CACHE_TYPE_INST = 2,
90 CACHE_TYPE_UNIFIED = 3
91 };
93 union _cpuid4_leaf_eax {
94 struct {
95 enum _cache_type type:5;
96 unsigned int level:3;
97 unsigned int is_self_initializing:1;
98 unsigned int is_fully_associative:1;
99 unsigned int reserved:4;
100 unsigned int num_threads_sharing:12;
101 unsigned int num_cores_on_die:6;
102 } split;
103 u32 full;
104 };
106 union _cpuid4_leaf_ebx {
107 struct {
108 unsigned int coherency_line_size:12;
109 unsigned int physical_line_partition:10;
110 unsigned int ways_of_associativity:10;
111 } split;
112 u32 full;
113 };
115 union _cpuid4_leaf_ecx {
116 struct {
117 unsigned int number_of_sets:32;
118 } split;
119 u32 full;
120 };
122 struct _cpuid4_info {
123 union _cpuid4_leaf_eax eax;
124 union _cpuid4_leaf_ebx ebx;
125 union _cpuid4_leaf_ecx ecx;
126 unsigned long size;
127 cpumask_t shared_cpu_map;
128 };
130 unsigned short num_cache_leaves;
132 /* AMD doesn't have CPUID4. Emulate it here to report the same
133 information to the user. This makes some assumptions about the machine:
134 L2 not shared, no SMT etc. that is currently true on AMD CPUs.
136 In theory the TLBs could be reported as fake type (they are in "dummy").
137 Maybe later */
138 union l1_cache {
139 struct {
140 unsigned line_size : 8;
141 unsigned lines_per_tag : 8;
142 unsigned assoc : 8;
143 unsigned size_in_kb : 8;
144 };
145 unsigned val;
146 };
148 union l2_cache {
149 struct {
150 unsigned line_size : 8;
151 unsigned lines_per_tag : 4;
152 unsigned assoc : 4;
153 unsigned size_in_kb : 16;
154 };
155 unsigned val;
156 };
158 union l3_cache {
159 struct {
160 unsigned line_size : 8;
161 unsigned lines_per_tag : 4;
162 unsigned assoc : 4;
163 unsigned res : 2;
164 unsigned size_encoded : 14;
165 };
166 unsigned val;
167 };
169 static const unsigned short assocs[] = {
170 [1] = 1, [2] = 2, [4] = 4, [6] = 8,
171 [8] = 16, [0xa] = 32, [0xb] = 48,
172 [0xc] = 64,
173 [0xf] = 0xffff // ??
174 };
176 static const unsigned char levels[] = { 1, 1, 2, 3 };
177 static const unsigned char types[] = { 1, 2, 3, 3 };
179 static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
180 union _cpuid4_leaf_ebx *ebx,
181 union _cpuid4_leaf_ecx *ecx)
182 {
183 unsigned dummy;
184 unsigned line_size, lines_per_tag, assoc, size_in_kb;
185 union l1_cache l1i, l1d;
186 union l2_cache l2;
187 union l3_cache l3;
188 union l1_cache *l1 = &l1d;
190 eax->full = 0;
191 ebx->full = 0;
192 ecx->full = 0;
194 cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
195 cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
197 switch (leaf) {
198 case 1:
199 l1 = &l1i;
200 case 0:
201 if (!l1->val)
202 return;
203 assoc = l1->assoc;
204 line_size = l1->line_size;
205 lines_per_tag = l1->lines_per_tag;
206 size_in_kb = l1->size_in_kb;
207 break;
208 case 2:
209 if (!l2.val)
210 return;
211 assoc = l2.assoc;
212 line_size = l2.line_size;
213 lines_per_tag = l2.lines_per_tag;
214 /* cpu_data has errata corrections for K7 applied */
215 size_in_kb = current_cpu_data.x86_cache_size;
216 break;
217 case 3:
218 if (!l3.val)
219 return;
220 assoc = l3.assoc;
221 line_size = l3.line_size;
222 lines_per_tag = l3.lines_per_tag;
223 size_in_kb = l3.size_encoded * 512;
224 break;
225 default:
226 return;
227 }
229 eax->split.is_self_initializing = 1;
230 eax->split.type = types[leaf];
231 eax->split.level = levels[leaf];
232 if (leaf == 3)
233 eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
234 else
235 eax->split.num_threads_sharing = 0;
236 eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
239 if (assoc == 0xf)
240 eax->split.is_fully_associative = 1;
241 ebx->split.coherency_line_size = line_size - 1;
242 ebx->split.ways_of_associativity = assocs[assoc] - 1;
243 ebx->split.physical_line_partition = lines_per_tag - 1;
244 ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
245 (ebx->split.ways_of_associativity + 1) - 1;
246 }
248 static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
249 {
250 union _cpuid4_leaf_eax eax;
251 union _cpuid4_leaf_ebx ebx;
252 union _cpuid4_leaf_ecx ecx;
253 unsigned edx;
255 if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
256 amd_cpuid4(index, &eax, &ebx, &ecx);
257 else
258 cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
259 if (eax.split.type == CACHE_TYPE_NULL)
260 return -EIO; /* better error ? */
262 this_leaf->eax = eax;
263 this_leaf->ebx = ebx;
264 this_leaf->ecx = ecx;
265 this_leaf->size = (ecx.split.number_of_sets + 1) *
266 (ebx.split.coherency_line_size + 1) *
267 (ebx.split.physical_line_partition + 1) *
268 (ebx.split.ways_of_associativity + 1);
269 return 0;
270 }
272 static int __cpuinit find_num_cache_leaves(void)
273 {
274 unsigned int eax, ebx, ecx, edx;
275 union _cpuid4_leaf_eax cache_eax;
276 int i = -1;
278 do {
279 ++i;
280 /* Do cpuid(4) loop to find out num_cache_leaves */
281 cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
282 cache_eax.full = eax;
283 } while (cache_eax.split.type != CACHE_TYPE_NULL);
284 return i;
285 }
287 unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
288 {
289 unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
290 unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
291 unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
292 unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
294 if (c->cpuid_level > 3) {
295 static int is_initialized;
297 if (is_initialized == 0) {
298 /* Init num_cache_leaves from boot CPU */
299 num_cache_leaves = find_num_cache_leaves();
300 is_initialized++;
301 }
303 /*
304 * Whenever possible use cpuid(4), deterministic cache
305 * parameters cpuid leaf to find the cache details
306 */
307 for (i = 0; i < num_cache_leaves; i++) {
308 struct _cpuid4_info this_leaf;
310 int retval;
312 retval = cpuid4_cache_lookup(i, &this_leaf);
313 if (retval >= 0) {
314 switch(this_leaf.eax.split.level) {
315 case 1:
316 if (this_leaf.eax.split.type ==
317 CACHE_TYPE_DATA)
318 new_l1d = this_leaf.size/1024;
319 else if (this_leaf.eax.split.type ==
320 CACHE_TYPE_INST)
321 new_l1i = this_leaf.size/1024;
322 break;
323 case 2:
324 new_l2 = this_leaf.size/1024;
325 num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
326 index_msb = get_count_order(num_threads_sharing);
327 l2_id = c->apicid >> index_msb;
328 break;
329 case 3:
330 new_l3 = this_leaf.size/1024;
331 num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
332 index_msb = get_count_order(num_threads_sharing);
333 l3_id = c->apicid >> index_msb;
334 break;
335 default:
336 break;
337 }
338 }
339 }
340 }
341 /*
342 * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
343 * trace cache
344 */
345 if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
346 /* supports eax=2 call */
347 int i, j, n;
348 int regs[4];
349 unsigned char *dp = (unsigned char *)regs;
350 int only_trace = 0;
352 if (num_cache_leaves != 0 && c->x86 == 15)
353 only_trace = 1;
355 /* Number of times to iterate */
356 n = cpuid_eax(2) & 0xFF;
358 for ( i = 0 ; i < n ; i++ ) {
359 cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
361 /* If bit 31 is set, this is an unknown format */
362 for ( j = 0 ; j < 3 ; j++ ) {
363 if ( regs[j] < 0 ) regs[j] = 0;
364 }
366 /* Byte 0 is level count, not a descriptor */
367 for ( j = 1 ; j < 16 ; j++ ) {
368 unsigned char des = dp[j];
369 unsigned char k = 0;
371 /* look up this descriptor in the table */
372 while (cache_table[k].descriptor != 0)
373 {
374 if (cache_table[k].descriptor == des) {
375 if (only_trace && cache_table[k].cache_type != LVL_TRACE)
376 break;
377 switch (cache_table[k].cache_type) {
378 case LVL_1_INST:
379 l1i += cache_table[k].size;
380 break;
381 case LVL_1_DATA:
382 l1d += cache_table[k].size;
383 break;
384 case LVL_2:
385 l2 += cache_table[k].size;
386 break;
387 case LVL_3:
388 l3 += cache_table[k].size;
389 break;
390 case LVL_TRACE:
391 trace += cache_table[k].size;
392 break;
393 }
395 break;
396 }
398 k++;
399 }
400 }
401 }
402 }
404 if (new_l1d)
405 l1d = new_l1d;
407 if (new_l1i)
408 l1i = new_l1i;
410 if (new_l2) {
411 l2 = new_l2;
412 }
414 if (new_l3) {
415 l3 = new_l3;
416 }
418 if (trace)
419 printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
420 else if ( l1i )
421 printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
423 if (l1d)
424 printk(", L1 D cache: %dK\n", l1d);
425 else
426 printk("\n");
428 if (l2)
429 printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
431 if (l3)
432 printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
434 c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
436 return l2;
437 }