~ubuntu-branches/ubuntu/utopic/xen/utopic

« back to all changes in this revision

Viewing changes to xen/arch/x86/cpu/intel_cacheinfo.c

  • Committer: Bazaar Package Importer
  • Author(s): Bastian Blank
  • Date: 2010-05-06 15:47:38 UTC
  • mto: (1.3.1) (15.1.1 sid) (4.1.1 experimental)
  • mto: This revision was merged to the branch mainline in revision 3.
  • Revision ID: james.westby@ubuntu.com-20100506154738-agoz0rlafrh1fnq7
Tags: upstream-4.0.0
ImportĀ upstreamĀ versionĀ 4.0.0

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
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
 */
 
9
 
 
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>
 
15
 
 
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
 
21
 
 
22
struct _cache_table
 
23
{
 
24
        unsigned char descriptor;
 
25
        char cache_type;
 
26
        short size;
 
27
};
 
28
 
 
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
};
 
83
 
 
84
 
 
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
};
 
92
 
 
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
};
 
105
 
 
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
};
 
114
 
 
115
union _cpuid4_leaf_ecx {
 
116
        struct {
 
117
                unsigned int            number_of_sets:32;
 
118
        } split;
 
119
        u32 full;
 
120
};
 
121
 
 
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
};
 
129
 
 
130
unsigned short                  num_cache_leaves;
 
131
 
 
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.
 
135
 
 
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
};
 
147
 
 
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
};
 
157
 
 
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
};
 
168
 
 
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
};
 
175
 
 
176
static const unsigned char levels[] = { 1, 1, 2, 3 };
 
177
static const unsigned char types[] = { 1, 2, 3, 3 };
 
178
 
 
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;
 
189
 
 
190
        eax->full = 0;
 
191
        ebx->full = 0;
 
192
        ecx->full = 0;
 
193
 
 
194
        cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
 
195
        cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
 
196
 
 
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
        }
 
228
 
 
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;
 
237
 
 
238
 
 
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
}
 
247
 
 
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;
 
254
 
 
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 ? */
 
261
 
 
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
}
 
271
 
 
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;
 
277
 
 
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
}
 
286
 
 
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;
 
293
 
 
294
        if (c->cpuid_level > 3) {
 
295
                static int is_initialized;
 
296
 
 
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
                }
 
302
 
 
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;
 
309
 
 
310
                        int retval;
 
311
 
 
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;
 
351
 
 
352
                if (num_cache_leaves != 0 && c->x86 == 15)
 
353
                        only_trace = 1;
 
354
 
 
355
                /* Number of times to iterate */
 
356
                n = cpuid_eax(2) & 0xFF;
 
357
 
 
358
                for ( i = 0 ; i < n ; i++ ) {
 
359
                        cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
 
360
 
 
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
                        }
 
365
 
 
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;
 
370
 
 
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
                                                }
 
394
 
 
395
                                                break;
 
396
                                        }
 
397
 
 
398
                                        k++;
 
399
                                }
 
400
                        }
 
401
                }
 
402
        }
 
403
 
 
404
        if (new_l1d)
 
405
                l1d = new_l1d;
 
406
 
 
407
        if (new_l1i)
 
408
                l1i = new_l1i;
 
409
 
 
410
        if (new_l2) {
 
411
                l2 = new_l2;
 
412
        }
 
413
 
 
414
        if (new_l3) {
 
415
                l3 = new_l3;
 
416
        }
 
417
 
 
418
        if (opt_cpu_info) {
 
419
                if (trace)
 
420
                        printk("CPU: Trace cache: %dK uops", trace);
 
421
                else if ( l1i )
 
422
                        printk("CPU: L1 I cache: %dK", l1i);
 
423
 
 
424
                if (l1d)
 
425
                        printk(", L1 D cache: %dK\n", l1d);
 
426
                else
 
427
                        printk("\n");
 
428
 
 
429
                if (l2)
 
430
                        printk("CPU: L2 cache: %dK\n", l2);
 
431
 
 
432
                if (l3)
 
433
                        printk("CPU: L3 cache: %dK\n", l3);
 
434
        }
 
435
 
 
436
        c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
 
437
 
 
438
        return l2;
 
439
}