OpenCores
URL https://opencores.org/ocsvn/or1k_soc_on_altera_embedded_dev_kit/or1k_soc_on_altera_embedded_dev_kit/trunk

Subversion Repositories or1k_soc_on_altera_embedded_dev_kit

[/] [or1k_soc_on_altera_embedded_dev_kit/] [trunk/] [linux-2.6/] [linux-2.6.24/] [arch/] [x86/] [kernel/] [cpu/] [intel_cacheinfo.c] - Blame information for rev 3

Details | Compare with Previous | View Log

Line No. Rev Author Line
1 3 xianfeng
/*
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 <linux/init.h>
11
#include <linux/slab.h>
12
#include <linux/device.h>
13
#include <linux/compiler.h>
14
#include <linux/cpu.h>
15
#include <linux/sched.h>
16
 
17
#include <asm/processor.h>
18
#include <asm/smp.h>
19
 
20
#define LVL_1_INST      1
21
#define LVL_1_DATA      2
22
#define LVL_2           3
23
#define LVL_3           4
24
#define LVL_TRACE       5
25
 
26
struct _cache_table
27
{
28
        unsigned char descriptor;
29
        char cache_type;
30
        short size;
31
};
32
 
33
/* all the cache descriptor types we care about (no TLB or trace cache entries) */
34
static struct _cache_table cache_table[] __cpuinitdata =
35
{
36
        { 0x06, LVL_1_INST, 8 },        /* 4-way set assoc, 32 byte line size */
37
        { 0x08, LVL_1_INST, 16 },       /* 4-way set assoc, 32 byte line size */
38
        { 0x0a, LVL_1_DATA, 8 },        /* 2 way set assoc, 32 byte line size */
39
        { 0x0c, LVL_1_DATA, 16 },       /* 4-way set assoc, 32 byte line size */
40
        { 0x22, LVL_3,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
41
        { 0x23, LVL_3,      1024 },     /* 8-way set assoc, sectored cache, 64 byte line size */
42
        { 0x25, LVL_3,      2048 },     /* 8-way set assoc, sectored cache, 64 byte line size */
43
        { 0x29, LVL_3,      4096 },     /* 8-way set assoc, sectored cache, 64 byte line size */
44
        { 0x2c, LVL_1_DATA, 32 },       /* 8-way set assoc, 64 byte line size */
45
        { 0x30, LVL_1_INST, 32 },       /* 8-way set assoc, 64 byte line size */
46
        { 0x39, LVL_2,      128 },      /* 4-way set assoc, sectored cache, 64 byte line size */
47
        { 0x3a, LVL_2,      192 },      /* 6-way set assoc, sectored cache, 64 byte line size */
48
        { 0x3b, LVL_2,      128 },      /* 2-way set assoc, sectored cache, 64 byte line size */
49
        { 0x3c, LVL_2,      256 },      /* 4-way set assoc, sectored cache, 64 byte line size */
50
        { 0x3d, LVL_2,      384 },      /* 6-way set assoc, sectored cache, 64 byte line size */
51
        { 0x3e, LVL_2,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
52
        { 0x3f, LVL_2,      256 },      /* 2-way set assoc, 64 byte line size */
53
        { 0x41, LVL_2,      128 },      /* 4-way set assoc, 32 byte line size */
54
        { 0x42, LVL_2,      256 },      /* 4-way set assoc, 32 byte line size */
55
        { 0x43, LVL_2,      512 },      /* 4-way set assoc, 32 byte line size */
56
        { 0x44, LVL_2,      1024 },     /* 4-way set assoc, 32 byte line size */
57
        { 0x45, LVL_2,      2048 },     /* 4-way set assoc, 32 byte line size */
58
        { 0x46, LVL_3,      4096 },     /* 4-way set assoc, 64 byte line size */
59
        { 0x47, LVL_3,      8192 },     /* 8-way set assoc, 64 byte line size */
60
        { 0x49, LVL_3,      4096 },     /* 16-way set assoc, 64 byte line size */
61
        { 0x4a, LVL_3,      6144 },     /* 12-way set assoc, 64 byte line size */
62
        { 0x4b, LVL_3,      8192 },     /* 16-way set assoc, 64 byte line size */
63
        { 0x4c, LVL_3,     12288 },     /* 12-way set assoc, 64 byte line size */
64
        { 0x4d, LVL_3,     16384 },     /* 16-way set assoc, 64 byte line size */
65
        { 0x60, LVL_1_DATA, 16 },       /* 8-way set assoc, sectored cache, 64 byte line size */
66
        { 0x66, LVL_1_DATA, 8 },        /* 4-way set assoc, sectored cache, 64 byte line size */
67
        { 0x67, LVL_1_DATA, 16 },       /* 4-way set assoc, sectored cache, 64 byte line size */
68
        { 0x68, LVL_1_DATA, 32 },       /* 4-way set assoc, sectored cache, 64 byte line size */
69
        { 0x70, LVL_TRACE,  12 },       /* 8-way set assoc */
70
        { 0x71, LVL_TRACE,  16 },       /* 8-way set assoc */
71
        { 0x72, LVL_TRACE,  32 },       /* 8-way set assoc */
72
        { 0x73, LVL_TRACE,  64 },       /* 8-way set assoc */
73
        { 0x78, LVL_2,    1024 },       /* 4-way set assoc, 64 byte line size */
74
        { 0x79, LVL_2,     128 },       /* 8-way set assoc, sectored cache, 64 byte line size */
75
        { 0x7a, LVL_2,     256 },       /* 8-way set assoc, sectored cache, 64 byte line size */
76
        { 0x7b, LVL_2,     512 },       /* 8-way set assoc, sectored cache, 64 byte line size */
77
        { 0x7c, LVL_2,    1024 },       /* 8-way set assoc, sectored cache, 64 byte line size */
78
        { 0x7d, LVL_2,    2048 },       /* 8-way set assoc, 64 byte line size */
79
        { 0x7f, LVL_2,     512 },       /* 2-way set assoc, 64 byte line size */
80
        { 0x82, LVL_2,     256 },       /* 8-way set assoc, 32 byte line size */
81
        { 0x83, LVL_2,     512 },       /* 8-way set assoc, 32 byte line size */
82
        { 0x84, LVL_2,    1024 },       /* 8-way set assoc, 32 byte line size */
83
        { 0x85, LVL_2,    2048 },       /* 8-way set assoc, 32 byte line size */
84
        { 0x86, LVL_2,     512 },       /* 4-way set assoc, 64 byte line size */
85
        { 0x87, LVL_2,    1024 },       /* 8-way set assoc, 64 byte line size */
86
        { 0x00, 0, 0}
87
};
88
 
89
 
90
enum _cache_type
91
{
92
        CACHE_TYPE_NULL = 0,
93
        CACHE_TYPE_DATA = 1,
94
        CACHE_TYPE_INST = 2,
95
        CACHE_TYPE_UNIFIED = 3
96
};
97
 
98
union _cpuid4_leaf_eax {
99
        struct {
100
                enum _cache_type        type:5;
101
                unsigned int            level:3;
102
                unsigned int            is_self_initializing:1;
103
                unsigned int            is_fully_associative:1;
104
                unsigned int            reserved:4;
105
                unsigned int            num_threads_sharing:12;
106
                unsigned int            num_cores_on_die:6;
107
        } split;
108
        u32 full;
109
};
110
 
111
union _cpuid4_leaf_ebx {
112
        struct {
113
                unsigned int            coherency_line_size:12;
114
                unsigned int            physical_line_partition:10;
115
                unsigned int            ways_of_associativity:10;
116
        } split;
117
        u32 full;
118
};
119
 
120
union _cpuid4_leaf_ecx {
121
        struct {
122
                unsigned int            number_of_sets:32;
123
        } split;
124
        u32 full;
125
};
126
 
127
struct _cpuid4_info {
128
        union _cpuid4_leaf_eax eax;
129
        union _cpuid4_leaf_ebx ebx;
130
        union _cpuid4_leaf_ecx ecx;
131
        unsigned long size;
132
        cpumask_t shared_cpu_map;
133
};
134
 
135
unsigned short                  num_cache_leaves;
136
 
137
/* AMD doesn't have CPUID4. Emulate it here to report the same
138
   information to the user.  This makes some assumptions about the machine:
139
   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
140
 
141
   In theory the TLBs could be reported as fake type (they are in "dummy").
142
   Maybe later */
143
union l1_cache {
144
        struct {
145
                unsigned line_size : 8;
146
                unsigned lines_per_tag : 8;
147
                unsigned assoc : 8;
148
                unsigned size_in_kb : 8;
149
        };
150
        unsigned val;
151
};
152
 
153
union l2_cache {
154
        struct {
155
                unsigned line_size : 8;
156
                unsigned lines_per_tag : 4;
157
                unsigned assoc : 4;
158
                unsigned size_in_kb : 16;
159
        };
160
        unsigned val;
161
};
162
 
163
union l3_cache {
164
        struct {
165
                unsigned line_size : 8;
166
                unsigned lines_per_tag : 4;
167
                unsigned assoc : 4;
168
                unsigned res : 2;
169
                unsigned size_encoded : 14;
170
        };
171
        unsigned val;
172
};
173
 
174
static unsigned short assocs[] __cpuinitdata = {
175
        [1] = 1, [2] = 2, [4] = 4, [6] = 8,
176
        [8] = 16, [0xa] = 32, [0xb] = 48,
177
        [0xc] = 64,
178
        [0xf] = 0xffff // ??
179
};
180
 
181
static unsigned char levels[] __cpuinitdata = { 1, 1, 2, 3 };
182
static unsigned char types[] __cpuinitdata = { 1, 2, 3, 3 };
183
 
184
static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
185
                       union _cpuid4_leaf_ebx *ebx,
186
                       union _cpuid4_leaf_ecx *ecx)
187
{
188
        unsigned dummy;
189
        unsigned line_size, lines_per_tag, assoc, size_in_kb;
190
        union l1_cache l1i, l1d;
191
        union l2_cache l2;
192
        union l3_cache l3;
193
        union l1_cache *l1 = &l1d;
194
 
195
        eax->full = 0;
196
        ebx->full = 0;
197
        ecx->full = 0;
198
 
199
        cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
200
        cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
201
 
202
        switch (leaf) {
203
        case 1:
204
                l1 = &l1i;
205
        case 0:
206
                if (!l1->val)
207
                        return;
208
                assoc = l1->assoc;
209
                line_size = l1->line_size;
210
                lines_per_tag = l1->lines_per_tag;
211
                size_in_kb = l1->size_in_kb;
212
                break;
213
        case 2:
214
                if (!l2.val)
215
                        return;
216
                assoc = l2.assoc;
217
                line_size = l2.line_size;
218
                lines_per_tag = l2.lines_per_tag;
219
                /* cpu_data has errata corrections for K7 applied */
220
                size_in_kb = current_cpu_data.x86_cache_size;
221
                break;
222
        case 3:
223
                if (!l3.val)
224
                        return;
225
                assoc = l3.assoc;
226
                line_size = l3.line_size;
227
                lines_per_tag = l3.lines_per_tag;
228
                size_in_kb = l3.size_encoded * 512;
229
                break;
230
        default:
231
                return;
232
        }
233
 
234
        eax->split.is_self_initializing = 1;
235
        eax->split.type = types[leaf];
236
        eax->split.level = levels[leaf];
237
        if (leaf == 3)
238
                eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1;
239
        else
240
                eax->split.num_threads_sharing = 0;
241
        eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
242
 
243
 
244
        if (assoc == 0xf)
245
                eax->split.is_fully_associative = 1;
246
        ebx->split.coherency_line_size = line_size - 1;
247
        ebx->split.ways_of_associativity = assocs[assoc] - 1;
248
        ebx->split.physical_line_partition = lines_per_tag - 1;
249
        ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
250
                (ebx->split.ways_of_associativity + 1) - 1;
251
}
252
 
253
static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
254
{
255
        union _cpuid4_leaf_eax  eax;
256
        union _cpuid4_leaf_ebx  ebx;
257
        union _cpuid4_leaf_ecx  ecx;
258
        unsigned                edx;
259
 
260
        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD)
261
                amd_cpuid4(index, &eax, &ebx, &ecx);
262
        else
263
                cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full,  &edx);
264
        if (eax.split.type == CACHE_TYPE_NULL)
265
                return -EIO; /* better error ? */
266
 
267
        this_leaf->eax = eax;
268
        this_leaf->ebx = ebx;
269
        this_leaf->ecx = ecx;
270
        this_leaf->size = (ecx.split.number_of_sets + 1) *
271
                (ebx.split.coherency_line_size + 1) *
272
                (ebx.split.physical_line_partition + 1) *
273
                (ebx.split.ways_of_associativity + 1);
274
        return 0;
275
}
276
 
277
static int __cpuinit find_num_cache_leaves(void)
278
{
279
        unsigned int            eax, ebx, ecx, edx;
280
        union _cpuid4_leaf_eax  cache_eax;
281
        int                     i = -1;
282
 
283
        do {
284
                ++i;
285
                /* Do cpuid(4) loop to find out num_cache_leaves */
286
                cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
287
                cache_eax.full = eax;
288
        } while (cache_eax.split.type != CACHE_TYPE_NULL);
289
        return i;
290
}
291
 
292
unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
293
{
294
        unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0; /* Cache sizes */
295
        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
296
        unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
297
        unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
298
#ifdef CONFIG_X86_HT
299
        unsigned int cpu = c->cpu_index;
300
#endif
301
 
302
        if (c->cpuid_level > 3) {
303
                static int is_initialized;
304
 
305
                if (is_initialized == 0) {
306
                        /* Init num_cache_leaves from boot CPU */
307
                        num_cache_leaves = find_num_cache_leaves();
308
                        is_initialized++;
309
                }
310
 
311
                /*
312
                 * Whenever possible use cpuid(4), deterministic cache
313
                 * parameters cpuid leaf to find the cache details
314
                 */
315
                for (i = 0; i < num_cache_leaves; i++) {
316
                        struct _cpuid4_info this_leaf;
317
 
318
                        int retval;
319
 
320
                        retval = cpuid4_cache_lookup(i, &this_leaf);
321
                        if (retval >= 0) {
322
                                switch(this_leaf.eax.split.level) {
323
                                    case 1:
324
                                        if (this_leaf.eax.split.type ==
325
                                                        CACHE_TYPE_DATA)
326
                                                new_l1d = this_leaf.size/1024;
327
                                        else if (this_leaf.eax.split.type ==
328
                                                        CACHE_TYPE_INST)
329
                                                new_l1i = this_leaf.size/1024;
330
                                        break;
331
                                    case 2:
332
                                        new_l2 = this_leaf.size/1024;
333
                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
334
                                        index_msb = get_count_order(num_threads_sharing);
335
                                        l2_id = c->apicid >> index_msb;
336
                                        break;
337
                                    case 3:
338
                                        new_l3 = this_leaf.size/1024;
339
                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
340
                                        index_msb = get_count_order(num_threads_sharing);
341
                                        l3_id = c->apicid >> index_msb;
342
                                        break;
343
                                    default:
344
                                        break;
345
                                }
346
                        }
347
                }
348
        }
349
        /*
350
         * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
351
         * trace cache
352
         */
353
        if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
354
                /* supports eax=2  call */
355
                int i, j, n;
356
                int regs[4];
357
                unsigned char *dp = (unsigned char *)regs;
358
                int only_trace = 0;
359
 
360
                if (num_cache_leaves != 0 && c->x86 == 15)
361
                        only_trace = 1;
362
 
363
                /* Number of times to iterate */
364
                n = cpuid_eax(2) & 0xFF;
365
 
366
                for ( i = 0 ; i < n ; i++ ) {
367
                        cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
368
 
369
                        /* If bit 31 is set, this is an unknown format */
370
                        for ( j = 0 ; j < 3 ; j++ ) {
371
                                if ( regs[j] < 0 ) regs[j] = 0;
372
                        }
373
 
374
                        /* Byte 0 is level count, not a descriptor */
375
                        for ( j = 1 ; j < 16 ; j++ ) {
376
                                unsigned char des = dp[j];
377
                                unsigned char k = 0;
378
 
379
                                /* look up this descriptor in the table */
380
                                while (cache_table[k].descriptor != 0)
381
                                {
382
                                        if (cache_table[k].descriptor == des) {
383
                                                if (only_trace && cache_table[k].cache_type != LVL_TRACE)
384
                                                        break;
385
                                                switch (cache_table[k].cache_type) {
386
                                                case LVL_1_INST:
387
                                                        l1i += cache_table[k].size;
388
                                                        break;
389
                                                case LVL_1_DATA:
390
                                                        l1d += cache_table[k].size;
391
                                                        break;
392
                                                case LVL_2:
393
                                                        l2 += cache_table[k].size;
394
                                                        break;
395
                                                case LVL_3:
396
                                                        l3 += cache_table[k].size;
397
                                                        break;
398
                                                case LVL_TRACE:
399
                                                        trace += cache_table[k].size;
400
                                                        break;
401
                                                }
402
 
403
                                                break;
404
                                        }
405
 
406
                                        k++;
407
                                }
408
                        }
409
                }
410
        }
411
 
412
        if (new_l1d)
413
                l1d = new_l1d;
414
 
415
        if (new_l1i)
416
                l1i = new_l1i;
417
 
418
        if (new_l2) {
419
                l2 = new_l2;
420
#ifdef CONFIG_X86_HT
421
                per_cpu(cpu_llc_id, cpu) = l2_id;
422
#endif
423
        }
424
 
425
        if (new_l3) {
426
                l3 = new_l3;
427
#ifdef CONFIG_X86_HT
428
                per_cpu(cpu_llc_id, cpu) = l3_id;
429
#endif
430
        }
431
 
432
        if (trace)
433
                printk (KERN_INFO "CPU: Trace cache: %dK uops", trace);
434
        else if ( l1i )
435
                printk (KERN_INFO "CPU: L1 I cache: %dK", l1i);
436
 
437
        if (l1d)
438
                printk(", L1 D cache: %dK\n", l1d);
439
        else
440
                printk("\n");
441
 
442
        if (l2)
443
                printk(KERN_INFO "CPU: L2 cache: %dK\n", l2);
444
 
445
        if (l3)
446
                printk(KERN_INFO "CPU: L3 cache: %dK\n", l3);
447
 
448
        c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
449
 
450
        return l2;
451
}
452
 
453
/* pointer to _cpuid4_info array (for each cache leaf) */
454
static struct _cpuid4_info *cpuid4_info[NR_CPUS];
455
#define CPUID4_INFO_IDX(x,y)    (&((cpuid4_info[x])[y]))
456
 
457
#ifdef CONFIG_SMP
458
static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
459
{
460
        struct _cpuid4_info     *this_leaf, *sibling_leaf;
461
        unsigned long num_threads_sharing;
462
        int index_msb, i;
463
        struct cpuinfo_x86 *c = &cpu_data(cpu);
464
 
465
        this_leaf = CPUID4_INFO_IDX(cpu, index);
466
        num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
467
 
468
        if (num_threads_sharing == 1)
469
                cpu_set(cpu, this_leaf->shared_cpu_map);
470
        else {
471
                index_msb = get_count_order(num_threads_sharing);
472
 
473
                for_each_online_cpu(i) {
474
                        if (cpu_data(i).apicid >> index_msb ==
475
                            c->apicid >> index_msb) {
476
                                cpu_set(i, this_leaf->shared_cpu_map);
477
                                if (i != cpu && cpuid4_info[i])  {
478
                                        sibling_leaf = CPUID4_INFO_IDX(i, index);
479
                                        cpu_set(cpu, sibling_leaf->shared_cpu_map);
480
                                }
481
                        }
482
                }
483
        }
484
}
485
static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
486
{
487
        struct _cpuid4_info     *this_leaf, *sibling_leaf;
488
        int sibling;
489
 
490
        this_leaf = CPUID4_INFO_IDX(cpu, index);
491
        for_each_cpu_mask(sibling, this_leaf->shared_cpu_map) {
492
                sibling_leaf = CPUID4_INFO_IDX(sibling, index);
493
                cpu_clear(cpu, sibling_leaf->shared_cpu_map);
494
        }
495
}
496
#else
497
static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) {}
498
static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index) {}
499
#endif
500
 
501
static void __cpuinit free_cache_attributes(unsigned int cpu)
502
{
503
        int i;
504
 
505
        for (i = 0; i < num_cache_leaves; i++)
506
                cache_remove_shared_cpu_map(cpu, i);
507
 
508
        kfree(cpuid4_info[cpu]);
509
        cpuid4_info[cpu] = NULL;
510
}
511
 
512
static int __cpuinit detect_cache_attributes(unsigned int cpu)
513
{
514
        struct _cpuid4_info     *this_leaf;
515
        unsigned long           j;
516
        int                     retval;
517
        cpumask_t               oldmask;
518
 
519
        if (num_cache_leaves == 0)
520
                return -ENOENT;
521
 
522
        cpuid4_info[cpu] = kzalloc(
523
            sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
524
        if (cpuid4_info[cpu] == NULL)
525
                return -ENOMEM;
526
 
527
        oldmask = current->cpus_allowed;
528
        retval = set_cpus_allowed(current, cpumask_of_cpu(cpu));
529
        if (retval)
530
                goto out;
531
 
532
        /* Do cpuid and store the results */
533
        for (j = 0; j < num_cache_leaves; j++) {
534
                this_leaf = CPUID4_INFO_IDX(cpu, j);
535
                retval = cpuid4_cache_lookup(j, this_leaf);
536
                if (unlikely(retval < 0)) {
537
                        int i;
538
 
539
                        for (i = 0; i < j; i++)
540
                                cache_remove_shared_cpu_map(cpu, i);
541
                        break;
542
                }
543
                cache_shared_cpu_map_setup(cpu, j);
544
        }
545
        set_cpus_allowed(current, oldmask);
546
 
547
out:
548
        if (retval) {
549
                kfree(cpuid4_info[cpu]);
550
                cpuid4_info[cpu] = NULL;
551
        }
552
 
553
        return retval;
554
}
555
 
556
#ifdef CONFIG_SYSFS
557
 
558
#include <linux/kobject.h>
559
#include <linux/sysfs.h>
560
 
561
extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */
562
 
563
/* pointer to kobject for cpuX/cache */
564
static struct kobject * cache_kobject[NR_CPUS];
565
 
566
struct _index_kobject {
567
        struct kobject kobj;
568
        unsigned int cpu;
569
        unsigned short index;
570
};
571
 
572
/* pointer to array of kobjects for cpuX/cache/indexY */
573
static struct _index_kobject *index_kobject[NR_CPUS];
574
#define INDEX_KOBJECT_PTR(x,y)    (&((index_kobject[x])[y]))
575
 
576
#define show_one_plus(file_name, object, val)                           \
577
static ssize_t show_##file_name                                         \
578
                        (struct _cpuid4_info *this_leaf, char *buf)     \
579
{                                                                       \
580
        return sprintf (buf, "%lu\n", (unsigned long)this_leaf->object + val); \
581
}
582
 
583
show_one_plus(level, eax.split.level, 0);
584
show_one_plus(coherency_line_size, ebx.split.coherency_line_size, 1);
585
show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);
586
show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);
587
show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);
588
 
589
static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf)
590
{
591
        return sprintf (buf, "%luK\n", this_leaf->size / 1024);
592
}
593
 
594
static ssize_t show_shared_cpu_map(struct _cpuid4_info *this_leaf, char *buf)
595
{
596
        char mask_str[NR_CPUS];
597
        cpumask_scnprintf(mask_str, NR_CPUS, this_leaf->shared_cpu_map);
598
        return sprintf(buf, "%s\n", mask_str);
599
}
600
 
601
static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
602
        switch(this_leaf->eax.split.type) {
603
            case CACHE_TYPE_DATA:
604
                return sprintf(buf, "Data\n");
605
                break;
606
            case CACHE_TYPE_INST:
607
                return sprintf(buf, "Instruction\n");
608
                break;
609
            case CACHE_TYPE_UNIFIED:
610
                return sprintf(buf, "Unified\n");
611
                break;
612
            default:
613
                return sprintf(buf, "Unknown\n");
614
                break;
615
        }
616
}
617
 
618
struct _cache_attr {
619
        struct attribute attr;
620
        ssize_t (*show)(struct _cpuid4_info *, char *);
621
        ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
622
};
623
 
624
#define define_one_ro(_name) \
625
static struct _cache_attr _name = \
626
        __ATTR(_name, 0444, show_##_name, NULL)
627
 
628
define_one_ro(level);
629
define_one_ro(type);
630
define_one_ro(coherency_line_size);
631
define_one_ro(physical_line_partition);
632
define_one_ro(ways_of_associativity);
633
define_one_ro(number_of_sets);
634
define_one_ro(size);
635
define_one_ro(shared_cpu_map);
636
 
637
static struct attribute * default_attrs[] = {
638
        &type.attr,
639
        &level.attr,
640
        &coherency_line_size.attr,
641
        &physical_line_partition.attr,
642
        &ways_of_associativity.attr,
643
        &number_of_sets.attr,
644
        &size.attr,
645
        &shared_cpu_map.attr,
646
        NULL
647
};
648
 
649
#define to_object(k) container_of(k, struct _index_kobject, kobj)
650
#define to_attr(a) container_of(a, struct _cache_attr, attr)
651
 
652
static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf)
653
{
654
        struct _cache_attr *fattr = to_attr(attr);
655
        struct _index_kobject *this_leaf = to_object(kobj);
656
        ssize_t ret;
657
 
658
        ret = fattr->show ?
659
                fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
660
                        buf) :
661
                0;
662
        return ret;
663
}
664
 
665
static ssize_t store(struct kobject * kobj, struct attribute * attr,
666
                     const char * buf, size_t count)
667
{
668
        return 0;
669
}
670
 
671
static struct sysfs_ops sysfs_ops = {
672
        .show   = show,
673
        .store  = store,
674
};
675
 
676
static struct kobj_type ktype_cache = {
677
        .sysfs_ops      = &sysfs_ops,
678
        .default_attrs  = default_attrs,
679
};
680
 
681
static struct kobj_type ktype_percpu_entry = {
682
        .sysfs_ops      = &sysfs_ops,
683
};
684
 
685
static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu)
686
{
687
        kfree(cache_kobject[cpu]);
688
        kfree(index_kobject[cpu]);
689
        cache_kobject[cpu] = NULL;
690
        index_kobject[cpu] = NULL;
691
        free_cache_attributes(cpu);
692
}
693
 
694
static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
695
{
696
        int err;
697
 
698
        if (num_cache_leaves == 0)
699
                return -ENOENT;
700
 
701
        err = detect_cache_attributes(cpu);
702
        if (err)
703
                return err;
704
 
705
        /* Allocate all required memory */
706
        cache_kobject[cpu] = kzalloc(sizeof(struct kobject), GFP_KERNEL);
707
        if (unlikely(cache_kobject[cpu] == NULL))
708
                goto err_out;
709
 
710
        index_kobject[cpu] = kzalloc(
711
            sizeof(struct _index_kobject ) * num_cache_leaves, GFP_KERNEL);
712
        if (unlikely(index_kobject[cpu] == NULL))
713
                goto err_out;
714
 
715
        return 0;
716
 
717
err_out:
718
        cpuid4_cache_sysfs_exit(cpu);
719
        return -ENOMEM;
720
}
721
 
722
static cpumask_t cache_dev_map = CPU_MASK_NONE;
723
 
724
/* Add/Remove cache interface for CPU device */
725
static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
726
{
727
        unsigned int cpu = sys_dev->id;
728
        unsigned long i, j;
729
        struct _index_kobject *this_object;
730
        int retval;
731
 
732
        retval = cpuid4_cache_sysfs_init(cpu);
733
        if (unlikely(retval < 0))
734
                return retval;
735
 
736
        cache_kobject[cpu]->parent = &sys_dev->kobj;
737
        kobject_set_name(cache_kobject[cpu], "%s", "cache");
738
        cache_kobject[cpu]->ktype = &ktype_percpu_entry;
739
        retval = kobject_register(cache_kobject[cpu]);
740
        if (retval < 0) {
741
                cpuid4_cache_sysfs_exit(cpu);
742
                return retval;
743
        }
744
 
745
        for (i = 0; i < num_cache_leaves; i++) {
746
                this_object = INDEX_KOBJECT_PTR(cpu,i);
747
                this_object->cpu = cpu;
748
                this_object->index = i;
749
                this_object->kobj.parent = cache_kobject[cpu];
750
                kobject_set_name(&(this_object->kobj), "index%1lu", i);
751
                this_object->kobj.ktype = &ktype_cache;
752
                retval = kobject_register(&(this_object->kobj));
753
                if (unlikely(retval)) {
754
                        for (j = 0; j < i; j++) {
755
                                kobject_unregister(
756
                                        &(INDEX_KOBJECT_PTR(cpu,j)->kobj));
757
                        }
758
                        kobject_unregister(cache_kobject[cpu]);
759
                        cpuid4_cache_sysfs_exit(cpu);
760
                        break;
761
                }
762
        }
763
        if (!retval)
764
                cpu_set(cpu, cache_dev_map);
765
 
766
        return retval;
767
}
768
 
769
static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
770
{
771
        unsigned int cpu = sys_dev->id;
772
        unsigned long i;
773
 
774
        if (cpuid4_info[cpu] == NULL)
775
                return;
776
        if (!cpu_isset(cpu, cache_dev_map))
777
                return;
778
        cpu_clear(cpu, cache_dev_map);
779
 
780
        for (i = 0; i < num_cache_leaves; i++)
781
                kobject_unregister(&(INDEX_KOBJECT_PTR(cpu,i)->kobj));
782
        kobject_unregister(cache_kobject[cpu]);
783
        cpuid4_cache_sysfs_exit(cpu);
784
}
785
 
786
static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
787
                                        unsigned long action, void *hcpu)
788
{
789
        unsigned int cpu = (unsigned long)hcpu;
790
        struct sys_device *sys_dev;
791
 
792
        sys_dev = get_cpu_sysdev(cpu);
793
        switch (action) {
794
        case CPU_ONLINE:
795
        case CPU_ONLINE_FROZEN:
796
                cache_add_dev(sys_dev);
797
                break;
798
        case CPU_DEAD:
799
        case CPU_DEAD_FROZEN:
800
                cache_remove_dev(sys_dev);
801
                break;
802
        }
803
        return NOTIFY_OK;
804
}
805
 
806
static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier =
807
{
808
        .notifier_call = cacheinfo_cpu_callback,
809
};
810
 
811
static int __cpuinit cache_sysfs_init(void)
812
{
813
        int i;
814
 
815
        if (num_cache_leaves == 0)
816
                return 0;
817
 
818
        for_each_online_cpu(i) {
819
                int err;
820
                struct sys_device *sys_dev = get_cpu_sysdev(i);
821
 
822
                err = cache_add_dev(sys_dev);
823
                if (err)
824
                        return err;
825
        }
826
        register_hotcpu_notifier(&cacheinfo_cpu_notifier);
827
        return 0;
828
}
829
 
830
device_initcall(cache_sysfs_init);
831
 
832
#endif

powered by: WebSVN 2.1.0

© copyright 1999-2024 OpenCores.org, equivalent to Oliscience, all rights reserved. OpenCores®, registered trademark.