linux/arch/x86/kernel/cpu/intel_cacheinfo.c
<<
>>
Prefs
   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 <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#include <linux/pci.h>
  17
  18#include <asm/processor.h>
  19#include <linux/smp.h>
  20#include <asm/k8.h>
  21
  22#define LVL_1_INST      1
  23#define LVL_1_DATA      2
  24#define LVL_2           3
  25#define LVL_3           4
  26#define LVL_TRACE       5
  27
  28struct _cache_table {
  29        unsigned char descriptor;
  30        char cache_type;
  31        short size;
  32};
  33
  34/* All the cache descriptor types we care about (no TLB or
  35   trace cache entries) */
  36
  37static const struct _cache_table __cpuinitconst cache_table[] =
  38{
  39        { 0x06, LVL_1_INST, 8 },        /* 4-way set assoc, 32 byte line size */
  40        { 0x08, LVL_1_INST, 16 },       /* 4-way set assoc, 32 byte line size */
  41        { 0x09, LVL_1_INST, 32 },       /* 4-way set assoc, 64 byte line size */
  42        { 0x0a, LVL_1_DATA, 8 },        /* 2 way set assoc, 32 byte line size */
  43        { 0x0c, LVL_1_DATA, 16 },       /* 4-way set assoc, 32 byte line size */
  44        { 0x0d, LVL_1_DATA, 16 },       /* 4-way set assoc, 64 byte line size */
  45        { 0x21, LVL_2,      256 },      /* 8-way set assoc, 64 byte line size */
  46        { 0x22, LVL_3,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
  47        { 0x23, LVL_3,      1024 },     /* 8-way set assoc, sectored cache, 64 byte line size */
  48        { 0x25, LVL_3,      2048 },     /* 8-way set assoc, sectored cache, 64 byte line size */
  49        { 0x29, LVL_3,      4096 },     /* 8-way set assoc, sectored cache, 64 byte line size */
  50        { 0x2c, LVL_1_DATA, 32 },       /* 8-way set assoc, 64 byte line size */
  51        { 0x30, LVL_1_INST, 32 },       /* 8-way set assoc, 64 byte line size */
  52        { 0x39, LVL_2,      128 },      /* 4-way set assoc, sectored cache, 64 byte line size */
  53        { 0x3a, LVL_2,      192 },      /* 6-way set assoc, sectored cache, 64 byte line size */
  54        { 0x3b, LVL_2,      128 },      /* 2-way set assoc, sectored cache, 64 byte line size */
  55        { 0x3c, LVL_2,      256 },      /* 4-way set assoc, sectored cache, 64 byte line size */
  56        { 0x3d, LVL_2,      384 },      /* 6-way set assoc, sectored cache, 64 byte line size */
  57        { 0x3e, LVL_2,      512 },      /* 4-way set assoc, sectored cache, 64 byte line size */
  58        { 0x3f, LVL_2,      256 },      /* 2-way set assoc, 64 byte line size */
  59        { 0x41, LVL_2,      128 },      /* 4-way set assoc, 32 byte line size */
  60        { 0x42, LVL_2,      256 },      /* 4-way set assoc, 32 byte line size */
  61        { 0x43, LVL_2,      512 },      /* 4-way set assoc, 32 byte line size */
  62        { 0x44, LVL_2,      1024 },     /* 4-way set assoc, 32 byte line size */
  63        { 0x45, LVL_2,      2048 },     /* 4-way set assoc, 32 byte line size */
  64        { 0x46, LVL_3,      4096 },     /* 4-way set assoc, 64 byte line size */
  65        { 0x47, LVL_3,      8192 },     /* 8-way set assoc, 64 byte line size */
  66        { 0x49, LVL_3,      4096 },     /* 16-way set assoc, 64 byte line size */
  67        { 0x4a, LVL_3,      6144 },     /* 12-way set assoc, 64 byte line size */
  68        { 0x4b, LVL_3,      8192 },     /* 16-way set assoc, 64 byte line size */
  69        { 0x4c, LVL_3,     12288 },     /* 12-way set assoc, 64 byte line size */
  70        { 0x4d, LVL_3,     16384 },     /* 16-way set assoc, 64 byte line size */
  71        { 0x4e, LVL_2,      6144 },     /* 24-way set assoc, 64 byte line size */
  72        { 0x60, LVL_1_DATA, 16 },       /* 8-way set assoc, sectored cache, 64 byte line size */
  73        { 0x66, LVL_1_DATA, 8 },        /* 4-way set assoc, sectored cache, 64 byte line size */
  74        { 0x67, LVL_1_DATA, 16 },       /* 4-way set assoc, sectored cache, 64 byte line size */
  75        { 0x68, LVL_1_DATA, 32 },       /* 4-way set assoc, sectored cache, 64 byte line size */
  76        { 0x70, LVL_TRACE,  12 },       /* 8-way set assoc */
  77        { 0x71, LVL_TRACE,  16 },       /* 8-way set assoc */
  78        { 0x72, LVL_TRACE,  32 },       /* 8-way set assoc */
  79        { 0x73, LVL_TRACE,  64 },       /* 8-way set assoc */
  80        { 0x78, LVL_2,    1024 },       /* 4-way set assoc, 64 byte line size */
  81        { 0x79, LVL_2,     128 },       /* 8-way set assoc, sectored cache, 64 byte line size */
  82        { 0x7a, LVL_2,     256 },       /* 8-way set assoc, sectored cache, 64 byte line size */
  83        { 0x7b, LVL_2,     512 },       /* 8-way set assoc, sectored cache, 64 byte line size */
  84        { 0x7c, LVL_2,    1024 },       /* 8-way set assoc, sectored cache, 64 byte line size */
  85        { 0x7d, LVL_2,    2048 },       /* 8-way set assoc, 64 byte line size */
  86        { 0x7f, LVL_2,     512 },       /* 2-way set assoc, 64 byte line size */
  87        { 0x82, LVL_2,     256 },       /* 8-way set assoc, 32 byte line size */
  88        { 0x83, LVL_2,     512 },       /* 8-way set assoc, 32 byte line size */
  89        { 0x84, LVL_2,    1024 },       /* 8-way set assoc, 32 byte line size */
  90        { 0x85, LVL_2,    2048 },       /* 8-way set assoc, 32 byte line size */
  91        { 0x86, LVL_2,     512 },       /* 4-way set assoc, 64 byte line size */
  92        { 0x87, LVL_2,    1024 },       /* 8-way set assoc, 64 byte line size */
  93        { 0xd0, LVL_3,     512 },       /* 4-way set assoc, 64 byte line size */
  94        { 0xd1, LVL_3,    1024 },       /* 4-way set assoc, 64 byte line size */
  95        { 0xd2, LVL_3,    2048 },       /* 4-way set assoc, 64 byte line size */
  96        { 0xd6, LVL_3,    1024 },       /* 8-way set assoc, 64 byte line size */
  97        { 0xd7, LVL_3,    2048 },       /* 8-way set assoc, 64 byte line size */
  98        { 0xd8, LVL_3,    4096 },       /* 12-way set assoc, 64 byte line size */
  99        { 0xdc, LVL_3,    2048 },       /* 12-way set assoc, 64 byte line size */
 100        { 0xdd, LVL_3,    4096 },       /* 12-way set assoc, 64 byte line size */
 101        { 0xde, LVL_3,    8192 },       /* 12-way set assoc, 64 byte line size */
 102        { 0xe2, LVL_3,    2048 },       /* 16-way set assoc, 64 byte line size */
 103        { 0xe3, LVL_3,    4096 },       /* 16-way set assoc, 64 byte line size */
 104        { 0xe4, LVL_3,    8192 },       /* 16-way set assoc, 64 byte line size */
 105        { 0xea, LVL_3,    12288 },      /* 24-way set assoc, 64 byte line size */
 106        { 0xeb, LVL_3,    18432 },      /* 24-way set assoc, 64 byte line size */
 107        { 0xec, LVL_3,    24576 },      /* 24-way set assoc, 64 byte line size */
 108        { 0x00, 0, 0}
 109};
 110
 111
 112enum _cache_type {
 113        CACHE_TYPE_NULL = 0,
 114        CACHE_TYPE_DATA = 1,
 115        CACHE_TYPE_INST = 2,
 116        CACHE_TYPE_UNIFIED = 3
 117};
 118
 119union _cpuid4_leaf_eax {
 120        struct {
 121                enum _cache_type        type:5;
 122                unsigned int            level:3;
 123                unsigned int            is_self_initializing:1;
 124                unsigned int            is_fully_associative:1;
 125                unsigned int            reserved:4;
 126                unsigned int            num_threads_sharing:12;
 127                unsigned int            num_cores_on_die:6;
 128        } split;
 129        u32 full;
 130};
 131
 132union _cpuid4_leaf_ebx {
 133        struct {
 134                unsigned int            coherency_line_size:12;
 135                unsigned int            physical_line_partition:10;
 136                unsigned int            ways_of_associativity:10;
 137        } split;
 138        u32 full;
 139};
 140
 141union _cpuid4_leaf_ecx {
 142        struct {
 143                unsigned int            number_of_sets:32;
 144        } split;
 145        u32 full;
 146};
 147
 148struct _cpuid4_info {
 149        union _cpuid4_leaf_eax eax;
 150        union _cpuid4_leaf_ebx ebx;
 151        union _cpuid4_leaf_ecx ecx;
 152        unsigned long size;
 153        unsigned long can_disable;
 154        DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
 155};
 156
 157/* subset of above _cpuid4_info w/o shared_cpu_map */
 158struct _cpuid4_info_regs {
 159        union _cpuid4_leaf_eax eax;
 160        union _cpuid4_leaf_ebx ebx;
 161        union _cpuid4_leaf_ecx ecx;
 162        unsigned long size;
 163        unsigned long can_disable;
 164};
 165
 166unsigned short                  num_cache_leaves;
 167
 168/* AMD doesn't have CPUID4. Emulate it here to report the same
 169   information to the user.  This makes some assumptions about the machine:
 170   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
 171
 172   In theory the TLBs could be reported as fake type (they are in "dummy").
 173   Maybe later */
 174union l1_cache {
 175        struct {
 176                unsigned line_size:8;
 177                unsigned lines_per_tag:8;
 178                unsigned assoc:8;
 179                unsigned size_in_kb:8;
 180        };
 181        unsigned val;
 182};
 183
 184union l2_cache {
 185        struct {
 186                unsigned line_size:8;
 187                unsigned lines_per_tag:4;
 188                unsigned assoc:4;
 189                unsigned size_in_kb:16;
 190        };
 191        unsigned val;
 192};
 193
 194union l3_cache {
 195        struct {
 196                unsigned line_size:8;
 197                unsigned lines_per_tag:4;
 198                unsigned assoc:4;
 199                unsigned res:2;
 200                unsigned size_encoded:14;
 201        };
 202        unsigned val;
 203};
 204
 205static const unsigned short __cpuinitconst assocs[] = {
 206        [1] = 1,
 207        [2] = 2,
 208        [4] = 4,
 209        [6] = 8,
 210        [8] = 16,
 211        [0xa] = 32,
 212        [0xb] = 48,
 213        [0xc] = 64,
 214        [0xd] = 96,
 215        [0xe] = 128,
 216        [0xf] = 0xffff /* fully associative - no way to show this currently */
 217};
 218
 219static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 };
 220static const unsigned char __cpuinitconst types[] = { 1, 2, 3, 3 };
 221
 222static void __cpuinit
 223amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 224                     union _cpuid4_leaf_ebx *ebx,
 225                     union _cpuid4_leaf_ecx *ecx)
 226{
 227        unsigned dummy;
 228        unsigned line_size, lines_per_tag, assoc, size_in_kb;
 229        union l1_cache l1i, l1d;
 230        union l2_cache l2;
 231        union l3_cache l3;
 232        union l1_cache *l1 = &l1d;
 233
 234        eax->full = 0;
 235        ebx->full = 0;
 236        ecx->full = 0;
 237
 238        cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
 239        cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
 240
 241        switch (leaf) {
 242        case 1:
 243                l1 = &l1i;
 244        case 0:
 245                if (!l1->val)
 246                        return;
 247                assoc = assocs[l1->assoc];
 248                line_size = l1->line_size;
 249                lines_per_tag = l1->lines_per_tag;
 250                size_in_kb = l1->size_in_kb;
 251                break;
 252        case 2:
 253                if (!l2.val)
 254                        return;
 255                assoc = assocs[l2.assoc];
 256                line_size = l2.line_size;
 257                lines_per_tag = l2.lines_per_tag;
 258                /* cpu_data has errata corrections for K7 applied */
 259                size_in_kb = current_cpu_data.x86_cache_size;
 260                break;
 261        case 3:
 262                if (!l3.val)
 263                        return;
 264                assoc = assocs[l3.assoc];
 265                line_size = l3.line_size;
 266                lines_per_tag = l3.lines_per_tag;
 267                size_in_kb = l3.size_encoded * 512;
 268                if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
 269                        size_in_kb = size_in_kb >> 1;
 270                        assoc = assoc >> 1;
 271                }
 272                break;
 273        default:
 274                return;
 275        }
 276
 277        eax->split.is_self_initializing = 1;
 278        eax->split.type = types[leaf];
 279        eax->split.level = levels[leaf];
 280        eax->split.num_threads_sharing = 0;
 281        eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;
 282
 283
 284        if (assoc == 0xffff)
 285                eax->split.is_fully_associative = 1;
 286        ebx->split.coherency_line_size = line_size - 1;
 287        ebx->split.ways_of_associativity = assoc - 1;
 288        ebx->split.physical_line_partition = lines_per_tag - 1;
 289        ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
 290                (ebx->split.ways_of_associativity + 1) - 1;
 291}
 292
 293static void __cpuinit
 294amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 295{
 296        if (index < 3)
 297                return;
 298
 299        if (boot_cpu_data.x86 == 0x11)
 300                return;
 301
 302        /* see erratum #382 */
 303        if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8))
 304                return;
 305
 306        this_leaf->can_disable = 1;
 307}
 308
 309static int
 310__cpuinit cpuid4_cache_lookup_regs(int index,
 311                                   struct _cpuid4_info_regs *this_leaf)
 312{
 313        union _cpuid4_leaf_eax  eax;
 314        union _cpuid4_leaf_ebx  ebx;
 315        union _cpuid4_leaf_ecx  ecx;
 316        unsigned                edx;
 317
 318        if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
 319                amd_cpuid4(index, &eax, &ebx, &ecx);
 320                if (boot_cpu_data.x86 >= 0x10)
 321                        amd_check_l3_disable(index, this_leaf);
 322        } else {
 323                cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
 324        }
 325
 326        if (eax.split.type == CACHE_TYPE_NULL)
 327                return -EIO; /* better error ? */
 328
 329        this_leaf->eax = eax;
 330        this_leaf->ebx = ebx;
 331        this_leaf->ecx = ecx;
 332        this_leaf->size = (ecx.split.number_of_sets          + 1) *
 333                          (ebx.split.coherency_line_size     + 1) *
 334                          (ebx.split.physical_line_partition + 1) *
 335                          (ebx.split.ways_of_associativity   + 1);
 336        return 0;
 337}
 338
 339static int __cpuinit find_num_cache_leaves(void)
 340{
 341        unsigned int            eax, ebx, ecx, edx;
 342        union _cpuid4_leaf_eax  cache_eax;
 343        int                     i = -1;
 344
 345        do {
 346                ++i;
 347                /* Do cpuid(4) loop to find out num_cache_leaves */
 348                cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
 349                cache_eax.full = eax;
 350        } while (cache_eax.split.type != CACHE_TYPE_NULL);
 351        return i;
 352}
 353
 354unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
 355{
 356        /* Cache sizes */
 357        unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0;
 358        unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
 359        unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
 360        unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
 361#ifdef CONFIG_X86_HT
 362        unsigned int cpu = c->cpu_index;
 363#endif
 364
 365        if (c->cpuid_level > 3) {
 366                static int is_initialized;
 367
 368                if (is_initialized == 0) {
 369                        /* Init num_cache_leaves from boot CPU */
 370                        num_cache_leaves = find_num_cache_leaves();
 371                        is_initialized++;
 372                }
 373
 374                /*
 375                 * Whenever possible use cpuid(4), deterministic cache
 376                 * parameters cpuid leaf to find the cache details
 377                 */
 378                for (i = 0; i < num_cache_leaves; i++) {
 379                        struct _cpuid4_info_regs this_leaf;
 380                        int retval;
 381
 382                        retval = cpuid4_cache_lookup_regs(i, &this_leaf);
 383                        if (retval >= 0) {
 384                                switch (this_leaf.eax.split.level) {
 385                                case 1:
 386                                        if (this_leaf.eax.split.type ==
 387                                                        CACHE_TYPE_DATA)
 388                                                new_l1d = this_leaf.size/1024;
 389                                        else if (this_leaf.eax.split.type ==
 390                                                        CACHE_TYPE_INST)
 391                                                new_l1i = this_leaf.size/1024;
 392                                        break;
 393                                case 2:
 394                                        new_l2 = this_leaf.size/1024;
 395                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
 396                                        index_msb = get_count_order(num_threads_sharing);
 397                                        l2_id = c->apicid >> index_msb;
 398                                        break;
 399                                case 3:
 400                                        new_l3 = this_leaf.size/1024;
 401                                        num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
 402                                        index_msb = get_count_order(
 403                                                        num_threads_sharing);
 404                                        l3_id = c->apicid >> index_msb;
 405                                        break;
 406                                default:
 407                                        break;
 408                                }
 409                        }
 410                }
 411        }
 412        /*
 413         * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
 414         * trace cache
 415         */
 416        if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
 417                /* supports eax=2  call */
 418                int j, n;
 419                unsigned int regs[4];
 420                unsigned char *dp = (unsigned char *)regs;
 421                int only_trace = 0;
 422
 423                if (num_cache_leaves != 0 && c->x86 == 15)
 424                        only_trace = 1;
 425
 426                /* Number of times to iterate */
 427                n = cpuid_eax(2) & 0xFF;
 428
 429                for (i = 0 ; i < n ; i++) {
 430                        cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);
 431
 432                        /* If bit 31 is set, this is an unknown format */
 433                        for (j = 0 ; j < 3 ; j++)
 434                                if (regs[j] & (1 << 31))
 435                                        regs[j] = 0;
 436
 437                        /* Byte 0 is level count, not a descriptor */
 438                        for (j = 1 ; j < 16 ; j++) {
 439                                unsigned char des = dp[j];
 440                                unsigned char k = 0;
 441
 442                                /* look up this descriptor in the table */
 443                                while (cache_table[k].descriptor != 0) {
 444                                        if (cache_table[k].descriptor == des) {
 445                                                if (only_trace && cache_table[k].cache_type != LVL_TRACE)
 446                                                        break;
 447                                                switch (cache_table[k].cache_type) {
 448                                                case LVL_1_INST:
 449                                                        l1i += cache_table[k].size;
 450                                                        break;
 451                                                case LVL_1_DATA:
 452                                                        l1d += cache_table[k].size;
 453                                                        break;
 454                                                case LVL_2:
 455                                                        l2 += cache_table[k].size;
 456                                                        break;
 457                                                case LVL_3:
 458                                                        l3 += cache_table[k].size;
 459                                                        break;
 460                                                case LVL_TRACE:
 461                                                        trace += cache_table[k].size;
 462                                                        break;
 463                                                }
 464
 465                                                break;
 466                                        }
 467
 468                                        k++;
 469                                }
 470                        }
 471                }
 472        }
 473
 474        if (new_l1d)
 475                l1d = new_l1d;
 476
 477        if (new_l1i)
 478                l1i = new_l1i;
 479
 480        if (new_l2) {
 481                l2 = new_l2;
 482#ifdef CONFIG_X86_HT
 483                per_cpu(cpu_llc_id, cpu) = l2_id;
 484#endif
 485        }
 486
 487        if (new_l3) {
 488                l3 = new_l3;
 489#ifdef CONFIG_X86_HT
 490                per_cpu(cpu_llc_id, cpu) = l3_id;
 491#endif
 492        }
 493
 494        c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));
 495
 496        return l2;
 497}
 498
 499#ifdef CONFIG_SYSFS
 500
 501/* pointer to _cpuid4_info array (for each cache leaf) */
 502static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
 503#define CPUID4_INFO_IDX(x, y)   (&((per_cpu(ici_cpuid4_info, x))[y]))
 504
 505#ifdef CONFIG_SMP
 506static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
 507{
 508        struct _cpuid4_info     *this_leaf, *sibling_leaf;
 509        unsigned long num_threads_sharing;
 510        int index_msb, i, sibling;
 511        struct cpuinfo_x86 *c = &cpu_data(cpu);
 512
 513        if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {
 514                for_each_cpu(i, c->llc_shared_map) {
 515                        if (!per_cpu(ici_cpuid4_info, i))
 516                                continue;
 517                        this_leaf = CPUID4_INFO_IDX(i, index);
 518                        for_each_cpu(sibling, c->llc_shared_map) {
 519                                if (!cpu_online(sibling))
 520                                        continue;
 521                                set_bit(sibling, this_leaf->shared_cpu_map);
 522                        }
 523                }
 524                return;
 525        }
 526        this_leaf = CPUID4_INFO_IDX(cpu, index);
 527        num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;
 528
 529        if (num_threads_sharing == 1)
 530                cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
 531        else {
 532                index_msb = get_count_order(num_threads_sharing);
 533
 534                for_each_online_cpu(i) {
 535                        if (cpu_data(i).apicid >> index_msb ==
 536                            c->apicid >> index_msb) {
 537                                cpumask_set_cpu(i,
 538                                        to_cpumask(this_leaf->shared_cpu_map));
 539                                if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
 540                                        sibling_leaf =
 541                                                CPUID4_INFO_IDX(i, index);
 542                                        cpumask_set_cpu(cpu, to_cpumask(
 543                                                sibling_leaf->shared_cpu_map));
 544                                }
 545                        }
 546                }
 547        }
 548}
 549static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
 550{
 551        struct _cpuid4_info     *this_leaf, *sibling_leaf;
 552        int sibling;
 553
 554        this_leaf = CPUID4_INFO_IDX(cpu, index);
 555        for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
 556                sibling_leaf = CPUID4_INFO_IDX(sibling, index);
 557                cpumask_clear_cpu(cpu,
 558                                  to_cpumask(sibling_leaf->shared_cpu_map));
 559        }
 560}
 561#else
 562static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
 563{
 564}
 565
 566static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
 567{
 568}
 569#endif
 570
 571static void __cpuinit free_cache_attributes(unsigned int cpu)
 572{
 573        int i;
 574
 575        for (i = 0; i < num_cache_leaves; i++)
 576                cache_remove_shared_cpu_map(cpu, i);
 577
 578        kfree(per_cpu(ici_cpuid4_info, cpu));
 579        per_cpu(ici_cpuid4_info, cpu) = NULL;
 580}
 581
 582static int
 583__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
 584{
 585        struct _cpuid4_info_regs *leaf_regs =
 586                (struct _cpuid4_info_regs *)this_leaf;
 587
 588        return cpuid4_cache_lookup_regs(index, leaf_regs);
 589}
 590
 591static void __cpuinit get_cpu_leaves(void *_retval)
 592{
 593        int j, *retval = _retval, cpu = smp_processor_id();
 594
 595        /* Do cpuid and store the results */
 596        for (j = 0; j < num_cache_leaves; j++) {
 597                struct _cpuid4_info *this_leaf;
 598                this_leaf = CPUID4_INFO_IDX(cpu, j);
 599                *retval = cpuid4_cache_lookup(j, this_leaf);
 600                if (unlikely(*retval < 0)) {
 601                        int i;
 602
 603                        for (i = 0; i < j; i++)
 604                                cache_remove_shared_cpu_map(cpu, i);
 605                        break;
 606                }
 607                cache_shared_cpu_map_setup(cpu, j);
 608        }
 609}
 610
 611static int __cpuinit detect_cache_attributes(unsigned int cpu)
 612{
 613        int                     retval;
 614
 615        if (num_cache_leaves == 0)
 616                return -ENOENT;
 617
 618        per_cpu(ici_cpuid4_info, cpu) = kzalloc(
 619            sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
 620        if (per_cpu(ici_cpuid4_info, cpu) == NULL)
 621                return -ENOMEM;
 622
 623        smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
 624        if (retval) {
 625                kfree(per_cpu(ici_cpuid4_info, cpu));
 626                per_cpu(ici_cpuid4_info, cpu) = NULL;
 627        }
 628
 629        return retval;
 630}
 631
 632#include <linux/kobject.h>
 633#include <linux/sysfs.h>
 634
 635extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */
 636
 637/* pointer to kobject for cpuX/cache */
 638static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
 639
 640struct _index_kobject {
 641        struct kobject kobj;
 642        unsigned int cpu;
 643        unsigned short index;
 644};
 645
 646/* pointer to array of kobjects for cpuX/cache/indexY */
 647static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
 648#define INDEX_KOBJECT_PTR(x, y)         (&((per_cpu(ici_index_kobject, x))[y]))
 649
 650#define show_one_plus(file_name, object, val)                           \
 651static ssize_t show_##file_name                                         \
 652                        (struct _cpuid4_info *this_leaf, char *buf)     \
 653{                                                                       \
 654        return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
 655}
 656
 657show_one_plus(level, eax.split.level, 0);
 658show_one_plus(coherency_line_size, ebx.split.coherency_line_size, 1);
 659show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);
 660show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);
 661show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);
 662
 663static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf)
 664{
 665        return sprintf(buf, "%luK\n", this_leaf->size / 1024);
 666}
 667
 668static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
 669                                        int type, char *buf)
 670{
 671        ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
 672        int n = 0;
 673
 674        if (len > 1) {
 675                const struct cpumask *mask;
 676
 677                mask = to_cpumask(this_leaf->shared_cpu_map);
 678                n = type ?
 679                        cpulist_scnprintf(buf, len-2, mask) :
 680                        cpumask_scnprintf(buf, len-2, mask);
 681                buf[n++] = '\n';
 682                buf[n] = '\0';
 683        }
 684        return n;
 685}
 686
 687static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf)
 688{
 689        return show_shared_cpu_map_func(leaf, 0, buf);
 690}
 691
 692static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf)
 693{
 694        return show_shared_cpu_map_func(leaf, 1, buf);
 695}
 696
 697static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf)
 698{
 699        switch (this_leaf->eax.split.type) {
 700        case CACHE_TYPE_DATA:
 701                return sprintf(buf, "Data\n");
 702        case CACHE_TYPE_INST:
 703                return sprintf(buf, "Instruction\n");
 704        case CACHE_TYPE_UNIFIED:
 705                return sprintf(buf, "Unified\n");
 706        default:
 707                return sprintf(buf, "Unknown\n");
 708        }
 709}
 710
 711#define to_object(k)    container_of(k, struct _index_kobject, kobj)
 712#define to_attr(a)      container_of(a, struct _cache_attr, attr)
 713
 714static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 715                                  unsigned int index)
 716{
 717        int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
 718        int node = cpu_to_node(cpu);
 719        struct pci_dev *dev = node_to_k8_nb_misc(node);
 720        unsigned int reg = 0;
 721
 722        if (!this_leaf->can_disable)
 723                return -EINVAL;
 724
 725        if (!dev)
 726                return -EINVAL;
 727
 728        pci_read_config_dword(dev, 0x1BC + index * 4, &reg);
 729        return sprintf(buf, "%x\n", reg);
 730}
 731
 732#define SHOW_CACHE_DISABLE(index)                                       \
 733static ssize_t                                                          \
 734show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf)   \
 735{                                                                       \
 736        return show_cache_disable(this_leaf, buf, index);               \
 737}
 738SHOW_CACHE_DISABLE(0)
 739SHOW_CACHE_DISABLE(1)
 740
 741static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 742        const char *buf, size_t count, unsigned int index)
 743{
 744        int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
 745        int node = cpu_to_node(cpu);
 746        struct pci_dev *dev = node_to_k8_nb_misc(node);
 747        unsigned long val = 0;
 748        unsigned int scrubber = 0;
 749
 750        if (!this_leaf->can_disable)
 751                return -EINVAL;
 752
 753        if (!capable(CAP_SYS_ADMIN))
 754                return -EPERM;
 755
 756        if (!dev)
 757                return -EINVAL;
 758
 759        if (strict_strtoul(buf, 10, &val) < 0)
 760                return -EINVAL;
 761
 762        val |= 0xc0000000;
 763
 764        pci_read_config_dword(dev, 0x58, &scrubber);
 765        scrubber &= ~0x1f000000;
 766        pci_write_config_dword(dev, 0x58, scrubber);
 767
 768        pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
 769        wbinvd();
 770        pci_write_config_dword(dev, 0x1BC + index * 4, val);
 771        return count;
 772}
 773
 774#define STORE_CACHE_DISABLE(index)                                      \
 775static ssize_t                                                          \
 776store_cache_disable_##index(struct _cpuid4_info *this_leaf,             \
 777                            const char *buf, size_t count)              \
 778{                                                                       \
 779        return store_cache_disable(this_leaf, buf, count, index);       \
 780}
 781STORE_CACHE_DISABLE(0)
 782STORE_CACHE_DISABLE(1)
 783
 784struct _cache_attr {
 785        struct attribute attr;
 786        ssize_t (*show)(struct _cpuid4_info *, char *);
 787        ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
 788};
 789
 790#define define_one_ro(_name) \
 791static struct _cache_attr _name = \
 792        __ATTR(_name, 0444, show_##_name, NULL)
 793
 794define_one_ro(level);
 795define_one_ro(type);
 796define_one_ro(coherency_line_size);
 797define_one_ro(physical_line_partition);
 798define_one_ro(ways_of_associativity);
 799define_one_ro(number_of_sets);
 800define_one_ro(size);
 801define_one_ro(shared_cpu_map);
 802define_one_ro(shared_cpu_list);
 803
 804static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
 805                show_cache_disable_0, store_cache_disable_0);
 806static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
 807                show_cache_disable_1, store_cache_disable_1);
 808
 809static struct attribute *default_attrs[] = {
 810        &type.attr,
 811        &level.attr,
 812        &coherency_line_size.attr,
 813        &physical_line_partition.attr,
 814        &ways_of_associativity.attr,
 815        &number_of_sets.attr,
 816        &size.attr,
 817        &shared_cpu_map.attr,
 818        &shared_cpu_list.attr,
 819        &cache_disable_0.attr,
 820        &cache_disable_1.attr,
 821        NULL
 822};
 823
 824static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
 825{
 826        struct _cache_attr *fattr = to_attr(attr);
 827        struct _index_kobject *this_leaf = to_object(kobj);
 828        ssize_t ret;
 829
 830        ret = fattr->show ?
 831                fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
 832                        buf) :
 833                0;
 834        return ret;
 835}
 836
 837static ssize_t store(struct kobject *kobj, struct attribute *attr,
 838                     const char *buf, size_t count)
 839{
 840        struct _cache_attr *fattr = to_attr(attr);
 841        struct _index_kobject *this_leaf = to_object(kobj);
 842        ssize_t ret;
 843
 844        ret = fattr->store ?
 845                fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
 846                        buf, count) :
 847                0;
 848        return ret;
 849}
 850
 851static struct sysfs_ops sysfs_ops = {
 852        .show   = show,
 853        .store  = store,
 854};
 855
 856static struct kobj_type ktype_cache = {
 857        .sysfs_ops      = &sysfs_ops,
 858        .default_attrs  = default_attrs,
 859};
 860
 861static struct kobj_type ktype_percpu_entry = {
 862        .sysfs_ops      = &sysfs_ops,
 863};
 864
 865static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu)
 866{
 867        kfree(per_cpu(ici_cache_kobject, cpu));
 868        kfree(per_cpu(ici_index_kobject, cpu));
 869        per_cpu(ici_cache_kobject, cpu) = NULL;
 870        per_cpu(ici_index_kobject, cpu) = NULL;
 871        free_cache_attributes(cpu);
 872}
 873
 874static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
 875{
 876        int err;
 877
 878        if (num_cache_leaves == 0)
 879                return -ENOENT;
 880
 881        err = detect_cache_attributes(cpu);
 882        if (err)
 883                return err;
 884
 885        /* Allocate all required memory */
 886        per_cpu(ici_cache_kobject, cpu) =
 887                kzalloc(sizeof(struct kobject), GFP_KERNEL);
 888        if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
 889                goto err_out;
 890
 891        per_cpu(ici_index_kobject, cpu) = kzalloc(
 892            sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
 893        if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
 894                goto err_out;
 895
 896        return 0;
 897
 898err_out:
 899        cpuid4_cache_sysfs_exit(cpu);
 900        return -ENOMEM;
 901}
 902
 903static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
 904
 905/* Add/Remove cache interface for CPU device */
 906static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
 907{
 908        unsigned int cpu = sys_dev->id;
 909        unsigned long i, j;
 910        struct _index_kobject *this_object;
 911        int retval;
 912
 913        retval = cpuid4_cache_sysfs_init(cpu);
 914        if (unlikely(retval < 0))
 915                return retval;
 916
 917        retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
 918                                      &ktype_percpu_entry,
 919                                      &sys_dev->kobj, "%s", "cache");
 920        if (retval < 0) {
 921                cpuid4_cache_sysfs_exit(cpu);
 922                return retval;
 923        }
 924
 925        for (i = 0; i < num_cache_leaves; i++) {
 926                this_object = INDEX_KOBJECT_PTR(cpu, i);
 927                this_object->cpu = cpu;
 928                this_object->index = i;
 929                retval = kobject_init_and_add(&(this_object->kobj),
 930                                              &ktype_cache,
 931                                              per_cpu(ici_cache_kobject, cpu),
 932                                              "index%1lu", i);
 933                if (unlikely(retval)) {
 934                        for (j = 0; j < i; j++)
 935                                kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
 936                        kobject_put(per_cpu(ici_cache_kobject, cpu));
 937                        cpuid4_cache_sysfs_exit(cpu);
 938                        return retval;
 939                }
 940                kobject_uevent(&(this_object->kobj), KOBJ_ADD);
 941        }
 942        cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
 943
 944        kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
 945        return 0;
 946}
 947
 948static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
 949{
 950        unsigned int cpu = sys_dev->id;
 951        unsigned long i;
 952
 953        if (per_cpu(ici_cpuid4_info, cpu) == NULL)
 954                return;
 955        if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
 956                return;
 957        cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
 958
 959        for (i = 0; i < num_cache_leaves; i++)
 960                kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
 961        kobject_put(per_cpu(ici_cache_kobject, cpu));
 962        cpuid4_cache_sysfs_exit(cpu);
 963}
 964
 965static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
 966                                        unsigned long action, void *hcpu)
 967{
 968        unsigned int cpu = (unsigned long)hcpu;
 969        struct sys_device *sys_dev;
 970
 971        sys_dev = get_cpu_sysdev(cpu);
 972        switch (action) {
 973        case CPU_ONLINE:
 974        case CPU_ONLINE_FROZEN:
 975                cache_add_dev(sys_dev);
 976                break;
 977        case CPU_DEAD:
 978        case CPU_DEAD_FROZEN:
 979                cache_remove_dev(sys_dev);
 980                break;
 981        }
 982        return NOTIFY_OK;
 983}
 984
 985static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = {
 986        .notifier_call = cacheinfo_cpu_callback,
 987};
 988
 989static int __cpuinit cache_sysfs_init(void)
 990{
 991        int i;
 992
 993        if (num_cache_leaves == 0)
 994                return 0;
 995
 996        for_each_online_cpu(i) {
 997                int err;
 998                struct sys_device *sys_dev = get_cpu_sysdev(i);
 999
1000                err = cache_add_dev(sys_dev);
1001                if (err)
1002                        return err;
1003        }
1004        register_hotcpu_notifier(&cacheinfo_cpu_notifier);
1005        return 0;
1006}
1007
1008device_initcall(cache_sysfs_init);
1009
1010#endif
1011
lxr.linux.no kindly hosted by Redpill Linpro AS, provider of Linux consulting and operations services since 1995.