Path: blob/master/arch/x86/kernel/cpu/intel_cacheinfo.c
10699 views
/*1* Routines to indentify caches on Intel CPU.2*3* Changes:4* Venkatesh Pallipadi : Adding cache identification through cpuid(4)5* Ashok Raj <[email protected]>: Work with CPU hotplug infrastructure.6* Andi Kleen / Andreas Herrmann : CPUID4 emulation on AMD.7*/89#include <linux/init.h>10#include <linux/slab.h>11#include <linux/device.h>12#include <linux/compiler.h>13#include <linux/cpu.h>14#include <linux/sched.h>15#include <linux/pci.h>1617#include <asm/processor.h>18#include <linux/smp.h>19#include <asm/amd_nb.h>20#include <asm/smp.h>2122#define LVL_1_INST 123#define LVL_1_DATA 224#define LVL_2 325#define LVL_3 426#define LVL_TRACE 52728struct _cache_table {29unsigned char descriptor;30char cache_type;31short size;32};3334#define MB(x) ((x) * 1024)3536/* All the cache descriptor types we care about (no TLB or37trace cache entries) */3839static const struct _cache_table __cpuinitconst cache_table[] =40{41{ 0x06, LVL_1_INST, 8 }, /* 4-way set assoc, 32 byte line size */42{ 0x08, LVL_1_INST, 16 }, /* 4-way set assoc, 32 byte line size */43{ 0x09, LVL_1_INST, 32 }, /* 4-way set assoc, 64 byte line size */44{ 0x0a, LVL_1_DATA, 8 }, /* 2 way set assoc, 32 byte line size */45{ 0x0c, LVL_1_DATA, 16 }, /* 4-way set assoc, 32 byte line size */46{ 0x0d, LVL_1_DATA, 16 }, /* 4-way set assoc, 64 byte line size */47{ 0x0e, LVL_1_DATA, 24 }, /* 6-way set assoc, 64 byte line size */48{ 0x21, LVL_2, 256 }, /* 8-way set assoc, 64 byte line size */49{ 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */50{ 0x23, LVL_3, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */51{ 0x25, LVL_3, MB(2) }, /* 8-way set assoc, sectored cache, 64 byte line size */52{ 0x29, LVL_3, MB(4) }, /* 8-way set assoc, sectored cache, 64 byte line size */53{ 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */54{ 0x30, LVL_1_INST, 32 }, /* 8-way set assoc, 64 byte line size */55{ 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */56{ 0x3a, LVL_2, 192 }, /* 6-way set assoc, sectored cache, 64 byte line size */57{ 0x3b, LVL_2, 128 }, /* 2-way set assoc, sectored cache, 64 byte line size */58{ 0x3c, LVL_2, 256 }, /* 4-way set assoc, sectored cache, 64 byte line size */59{ 0x3d, LVL_2, 384 }, /* 6-way set assoc, sectored cache, 64 byte line size */60{ 0x3e, LVL_2, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */61{ 0x3f, LVL_2, 256 }, /* 2-way set assoc, 64 byte line size */62{ 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */63{ 0x42, LVL_2, 256 }, /* 4-way set assoc, 32 byte line size */64{ 0x43, LVL_2, 512 }, /* 4-way set assoc, 32 byte line size */65{ 0x44, LVL_2, MB(1) }, /* 4-way set assoc, 32 byte line size */66{ 0x45, LVL_2, MB(2) }, /* 4-way set assoc, 32 byte line size */67{ 0x46, LVL_3, MB(4) }, /* 4-way set assoc, 64 byte line size */68{ 0x47, LVL_3, MB(8) }, /* 8-way set assoc, 64 byte line size */69{ 0x48, LVL_2, MB(3) }, /* 12-way set assoc, 64 byte line size */70{ 0x49, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */71{ 0x4a, LVL_3, MB(6) }, /* 12-way set assoc, 64 byte line size */72{ 0x4b, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */73{ 0x4c, LVL_3, MB(12) }, /* 12-way set assoc, 64 byte line size */74{ 0x4d, LVL_3, MB(16) }, /* 16-way set assoc, 64 byte line size */75{ 0x4e, LVL_2, MB(6) }, /* 24-way set assoc, 64 byte line size */76{ 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */77{ 0x66, LVL_1_DATA, 8 }, /* 4-way set assoc, sectored cache, 64 byte line size */78{ 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */79{ 0x68, LVL_1_DATA, 32 }, /* 4-way set assoc, sectored cache, 64 byte line size */80{ 0x70, LVL_TRACE, 12 }, /* 8-way set assoc */81{ 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */82{ 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */83{ 0x73, LVL_TRACE, 64 }, /* 8-way set assoc */84{ 0x78, LVL_2, MB(1) }, /* 4-way set assoc, 64 byte line size */85{ 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */86{ 0x7a, LVL_2, 256 }, /* 8-way set assoc, sectored cache, 64 byte line size */87{ 0x7b, LVL_2, 512 }, /* 8-way set assoc, sectored cache, 64 byte line size */88{ 0x7c, LVL_2, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */89{ 0x7d, LVL_2, MB(2) }, /* 8-way set assoc, 64 byte line size */90{ 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */91{ 0x80, LVL_2, 512 }, /* 8-way set assoc, 64 byte line size */92{ 0x82, LVL_2, 256 }, /* 8-way set assoc, 32 byte line size */93{ 0x83, LVL_2, 512 }, /* 8-way set assoc, 32 byte line size */94{ 0x84, LVL_2, MB(1) }, /* 8-way set assoc, 32 byte line size */95{ 0x85, LVL_2, MB(2) }, /* 8-way set assoc, 32 byte line size */96{ 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */97{ 0x87, LVL_2, MB(1) }, /* 8-way set assoc, 64 byte line size */98{ 0xd0, LVL_3, 512 }, /* 4-way set assoc, 64 byte line size */99{ 0xd1, LVL_3, MB(1) }, /* 4-way set assoc, 64 byte line size */100{ 0xd2, LVL_3, MB(2) }, /* 4-way set assoc, 64 byte line size */101{ 0xd6, LVL_3, MB(1) }, /* 8-way set assoc, 64 byte line size */102{ 0xd7, LVL_3, MB(2) }, /* 8-way set assoc, 64 byte line size */103{ 0xd8, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */104{ 0xdc, LVL_3, MB(2) }, /* 12-way set assoc, 64 byte line size */105{ 0xdd, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */106{ 0xde, LVL_3, MB(8) }, /* 12-way set assoc, 64 byte line size */107{ 0xe2, LVL_3, MB(2) }, /* 16-way set assoc, 64 byte line size */108{ 0xe3, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */109{ 0xe4, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */110{ 0xea, LVL_3, MB(12) }, /* 24-way set assoc, 64 byte line size */111{ 0xeb, LVL_3, MB(18) }, /* 24-way set assoc, 64 byte line size */112{ 0xec, LVL_3, MB(24) }, /* 24-way set assoc, 64 byte line size */113{ 0x00, 0, 0}114};115116117enum _cache_type {118CACHE_TYPE_NULL = 0,119CACHE_TYPE_DATA = 1,120CACHE_TYPE_INST = 2,121CACHE_TYPE_UNIFIED = 3122};123124union _cpuid4_leaf_eax {125struct {126enum _cache_type type:5;127unsigned int level:3;128unsigned int is_self_initializing:1;129unsigned int is_fully_associative:1;130unsigned int reserved:4;131unsigned int num_threads_sharing:12;132unsigned int num_cores_on_die:6;133} split;134u32 full;135};136137union _cpuid4_leaf_ebx {138struct {139unsigned int coherency_line_size:12;140unsigned int physical_line_partition:10;141unsigned int ways_of_associativity:10;142} split;143u32 full;144};145146union _cpuid4_leaf_ecx {147struct {148unsigned int number_of_sets:32;149} split;150u32 full;151};152153struct amd_l3_cache {154struct amd_northbridge *nb;155unsigned indices;156u8 subcaches[4];157};158159struct _cpuid4_info {160union _cpuid4_leaf_eax eax;161union _cpuid4_leaf_ebx ebx;162union _cpuid4_leaf_ecx ecx;163unsigned long size;164struct amd_l3_cache *l3;165DECLARE_BITMAP(shared_cpu_map, NR_CPUS);166};167168/* subset of above _cpuid4_info w/o shared_cpu_map */169struct _cpuid4_info_regs {170union _cpuid4_leaf_eax eax;171union _cpuid4_leaf_ebx ebx;172union _cpuid4_leaf_ecx ecx;173unsigned long size;174struct amd_l3_cache *l3;175};176177unsigned short num_cache_leaves;178179/* AMD doesn't have CPUID4. Emulate it here to report the same180information to the user. This makes some assumptions about the machine:181L2 not shared, no SMT etc. that is currently true on AMD CPUs.182183In theory the TLBs could be reported as fake type (they are in "dummy").184Maybe later */185union l1_cache {186struct {187unsigned line_size:8;188unsigned lines_per_tag:8;189unsigned assoc:8;190unsigned size_in_kb:8;191};192unsigned val;193};194195union l2_cache {196struct {197unsigned line_size:8;198unsigned lines_per_tag:4;199unsigned assoc:4;200unsigned size_in_kb:16;201};202unsigned val;203};204205union l3_cache {206struct {207unsigned line_size:8;208unsigned lines_per_tag:4;209unsigned assoc:4;210unsigned res:2;211unsigned size_encoded:14;212};213unsigned val;214};215216static const unsigned short __cpuinitconst assocs[] = {217[1] = 1,218[2] = 2,219[4] = 4,220[6] = 8,221[8] = 16,222[0xa] = 32,223[0xb] = 48,224[0xc] = 64,225[0xd] = 96,226[0xe] = 128,227[0xf] = 0xffff /* fully associative - no way to show this currently */228};229230static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 };231static const unsigned char __cpuinitconst types[] = { 1, 2, 3, 3 };232233static void __cpuinit234amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,235union _cpuid4_leaf_ebx *ebx,236union _cpuid4_leaf_ecx *ecx)237{238unsigned dummy;239unsigned line_size, lines_per_tag, assoc, size_in_kb;240union l1_cache l1i, l1d;241union l2_cache l2;242union l3_cache l3;243union l1_cache *l1 = &l1d;244245eax->full = 0;246ebx->full = 0;247ecx->full = 0;248249cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);250cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);251252switch (leaf) {253case 1:254l1 = &l1i;255case 0:256if (!l1->val)257return;258assoc = assocs[l1->assoc];259line_size = l1->line_size;260lines_per_tag = l1->lines_per_tag;261size_in_kb = l1->size_in_kb;262break;263case 2:264if (!l2.val)265return;266assoc = assocs[l2.assoc];267line_size = l2.line_size;268lines_per_tag = l2.lines_per_tag;269/* cpu_data has errata corrections for K7 applied */270size_in_kb = __this_cpu_read(cpu_info.x86_cache_size);271break;272case 3:273if (!l3.val)274return;275assoc = assocs[l3.assoc];276line_size = l3.line_size;277lines_per_tag = l3.lines_per_tag;278size_in_kb = l3.size_encoded * 512;279if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {280size_in_kb = size_in_kb >> 1;281assoc = assoc >> 1;282}283break;284default:285return;286}287288eax->split.is_self_initializing = 1;289eax->split.type = types[leaf];290eax->split.level = levels[leaf];291eax->split.num_threads_sharing = 0;292eax->split.num_cores_on_die = __this_cpu_read(cpu_info.x86_max_cores) - 1;293294295if (assoc == 0xffff)296eax->split.is_fully_associative = 1;297ebx->split.coherency_line_size = line_size - 1;298ebx->split.ways_of_associativity = assoc - 1;299ebx->split.physical_line_partition = lines_per_tag - 1;300ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /301(ebx->split.ways_of_associativity + 1) - 1;302}303304struct _cache_attr {305struct attribute attr;306ssize_t (*show)(struct _cpuid4_info *, char *, unsigned int);307ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count,308unsigned int);309};310311#ifdef CONFIG_AMD_NB312313/*314* L3 cache descriptors315*/316static void __cpuinit amd_calc_l3_indices(struct amd_l3_cache *l3)317{318unsigned int sc0, sc1, sc2, sc3;319u32 val = 0;320321pci_read_config_dword(l3->nb->misc, 0x1C4, &val);322323/* calculate subcache sizes */324l3->subcaches[0] = sc0 = !(val & BIT(0));325l3->subcaches[1] = sc1 = !(val & BIT(4));326l3->subcaches[2] = sc2 = !(val & BIT(8)) + !(val & BIT(9));327l3->subcaches[3] = sc3 = !(val & BIT(12)) + !(val & BIT(13));328329l3->indices = (max(max3(sc0, sc1, sc2), sc3) << 10) - 1;330}331332static void __cpuinit amd_init_l3_cache(struct _cpuid4_info_regs *this_leaf,333int index)334{335static struct amd_l3_cache *__cpuinitdata l3_caches;336int node;337338/* only for L3, and not in virtualized environments */339if (index < 3 || amd_nb_num() == 0)340return;341342/*343* Strictly speaking, the amount in @size below is leaked since it is344* never freed but this is done only on shutdown so it doesn't matter.345*/346if (!l3_caches) {347int size = amd_nb_num() * sizeof(struct amd_l3_cache);348349l3_caches = kzalloc(size, GFP_ATOMIC);350if (!l3_caches)351return;352}353354node = amd_get_nb_id(smp_processor_id());355356if (!l3_caches[node].nb) {357l3_caches[node].nb = node_to_amd_nb(node);358amd_calc_l3_indices(&l3_caches[node]);359}360361this_leaf->l3 = &l3_caches[node];362}363364/*365* check whether a slot used for disabling an L3 index is occupied.366* @l3: L3 cache descriptor367* @slot: slot number (0..1)368*369* @returns: the disabled index if used or negative value if slot free.370*/371int amd_get_l3_disable_slot(struct amd_l3_cache *l3, unsigned slot)372{373unsigned int reg = 0;374375pci_read_config_dword(l3->nb->misc, 0x1BC + slot * 4, ®);376377/* check whether this slot is activated already */378if (reg & (3UL << 30))379return reg & 0xfff;380381return -1;382}383384static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,385unsigned int slot)386{387int index;388389if (!this_leaf->l3 ||390!amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))391return -EINVAL;392393index = amd_get_l3_disable_slot(this_leaf->l3, slot);394if (index >= 0)395return sprintf(buf, "%d\n", index);396397return sprintf(buf, "FREE\n");398}399400#define SHOW_CACHE_DISABLE(slot) \401static ssize_t \402show_cache_disable_##slot(struct _cpuid4_info *this_leaf, char *buf, \403unsigned int cpu) \404{ \405return show_cache_disable(this_leaf, buf, slot); \406}407SHOW_CACHE_DISABLE(0)408SHOW_CACHE_DISABLE(1)409410static void amd_l3_disable_index(struct amd_l3_cache *l3, int cpu,411unsigned slot, unsigned long idx)412{413int i;414415idx |= BIT(30);416417/*418* disable index in all 4 subcaches419*/420for (i = 0; i < 4; i++) {421u32 reg = idx | (i << 20);422423if (!l3->subcaches[i])424continue;425426pci_write_config_dword(l3->nb->misc, 0x1BC + slot * 4, reg);427428/*429* We need to WBINVD on a core on the node containing the L3430* cache which indices we disable therefore a simple wbinvd()431* is not sufficient.432*/433wbinvd_on_cpu(cpu);434435reg |= BIT(31);436pci_write_config_dword(l3->nb->misc, 0x1BC + slot * 4, reg);437}438}439440/*441* disable a L3 cache index by using a disable-slot442*443* @l3: L3 cache descriptor444* @cpu: A CPU on the node containing the L3 cache445* @slot: slot number (0..1)446* @index: index to disable447*448* @return: 0 on success, error status on failure449*/450int amd_set_l3_disable_slot(struct amd_l3_cache *l3, int cpu, unsigned slot,451unsigned long index)452{453int ret = 0;454455/* check if @slot is already used or the index is already disabled */456ret = amd_get_l3_disable_slot(l3, slot);457if (ret >= 0)458return -EINVAL;459460if (index > l3->indices)461return -EINVAL;462463/* check whether the other slot has disabled the same index already */464if (index == amd_get_l3_disable_slot(l3, !slot))465return -EINVAL;466467amd_l3_disable_index(l3, cpu, slot, index);468469return 0;470}471472static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,473const char *buf, size_t count,474unsigned int slot)475{476unsigned long val = 0;477int cpu, err = 0;478479if (!capable(CAP_SYS_ADMIN))480return -EPERM;481482if (!this_leaf->l3 ||483!amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))484return -EINVAL;485486cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));487488if (strict_strtoul(buf, 10, &val) < 0)489return -EINVAL;490491err = amd_set_l3_disable_slot(this_leaf->l3, cpu, slot, val);492if (err) {493if (err == -EEXIST)494printk(KERN_WARNING "L3 disable slot %d in use!\n",495slot);496return err;497}498return count;499}500501#define STORE_CACHE_DISABLE(slot) \502static ssize_t \503store_cache_disable_##slot(struct _cpuid4_info *this_leaf, \504const char *buf, size_t count, \505unsigned int cpu) \506{ \507return store_cache_disable(this_leaf, buf, count, slot); \508}509STORE_CACHE_DISABLE(0)510STORE_CACHE_DISABLE(1)511512static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,513show_cache_disable_0, store_cache_disable_0);514static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,515show_cache_disable_1, store_cache_disable_1);516517static ssize_t518show_subcaches(struct _cpuid4_info *this_leaf, char *buf, unsigned int cpu)519{520if (!this_leaf->l3 || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))521return -EINVAL;522523return sprintf(buf, "%x\n", amd_get_subcaches(cpu));524}525526static ssize_t527store_subcaches(struct _cpuid4_info *this_leaf, const char *buf, size_t count,528unsigned int cpu)529{530unsigned long val;531532if (!capable(CAP_SYS_ADMIN))533return -EPERM;534535if (!this_leaf->l3 || !amd_nb_has_feature(AMD_NB_L3_PARTITIONING))536return -EINVAL;537538if (strict_strtoul(buf, 16, &val) < 0)539return -EINVAL;540541if (amd_set_subcaches(cpu, val))542return -EINVAL;543544return count;545}546547static struct _cache_attr subcaches =548__ATTR(subcaches, 0644, show_subcaches, store_subcaches);549550#else /* CONFIG_AMD_NB */551#define amd_init_l3_cache(x, y)552#endif /* CONFIG_AMD_NB */553554static int555__cpuinit cpuid4_cache_lookup_regs(int index,556struct _cpuid4_info_regs *this_leaf)557{558union _cpuid4_leaf_eax eax;559union _cpuid4_leaf_ebx ebx;560union _cpuid4_leaf_ecx ecx;561unsigned edx;562563if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {564amd_cpuid4(index, &eax, &ebx, &ecx);565amd_init_l3_cache(this_leaf, index);566} else {567cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);568}569570if (eax.split.type == CACHE_TYPE_NULL)571return -EIO; /* better error ? */572573this_leaf->eax = eax;574this_leaf->ebx = ebx;575this_leaf->ecx = ecx;576this_leaf->size = (ecx.split.number_of_sets + 1) *577(ebx.split.coherency_line_size + 1) *578(ebx.split.physical_line_partition + 1) *579(ebx.split.ways_of_associativity + 1);580return 0;581}582583static int __cpuinit find_num_cache_leaves(void)584{585unsigned int eax, ebx, ecx, edx;586union _cpuid4_leaf_eax cache_eax;587int i = -1;588589do {590++i;591/* Do cpuid(4) loop to find out num_cache_leaves */592cpuid_count(4, i, &eax, &ebx, &ecx, &edx);593cache_eax.full = eax;594} while (cache_eax.split.type != CACHE_TYPE_NULL);595return i;596}597598unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)599{600/* Cache sizes */601unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0;602unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */603unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */604unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;605#ifdef CONFIG_X86_HT606unsigned int cpu = c->cpu_index;607#endif608609if (c->cpuid_level > 3) {610static int is_initialized;611612if (is_initialized == 0) {613/* Init num_cache_leaves from boot CPU */614num_cache_leaves = find_num_cache_leaves();615is_initialized++;616}617618/*619* Whenever possible use cpuid(4), deterministic cache620* parameters cpuid leaf to find the cache details621*/622for (i = 0; i < num_cache_leaves; i++) {623struct _cpuid4_info_regs this_leaf;624int retval;625626retval = cpuid4_cache_lookup_regs(i, &this_leaf);627if (retval >= 0) {628switch (this_leaf.eax.split.level) {629case 1:630if (this_leaf.eax.split.type ==631CACHE_TYPE_DATA)632new_l1d = this_leaf.size/1024;633else if (this_leaf.eax.split.type ==634CACHE_TYPE_INST)635new_l1i = this_leaf.size/1024;636break;637case 2:638new_l2 = this_leaf.size/1024;639num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;640index_msb = get_count_order(num_threads_sharing);641l2_id = c->apicid >> index_msb;642break;643case 3:644new_l3 = this_leaf.size/1024;645num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;646index_msb = get_count_order(647num_threads_sharing);648l3_id = c->apicid >> index_msb;649break;650default:651break;652}653}654}655}656/*657* Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for658* trace cache659*/660if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {661/* supports eax=2 call */662int j, n;663unsigned int regs[4];664unsigned char *dp = (unsigned char *)regs;665int only_trace = 0;666667if (num_cache_leaves != 0 && c->x86 == 15)668only_trace = 1;669670/* Number of times to iterate */671n = cpuid_eax(2) & 0xFF;672673for (i = 0 ; i < n ; i++) {674cpuid(2, ®s[0], ®s[1], ®s[2], ®s[3]);675676/* If bit 31 is set, this is an unknown format */677for (j = 0 ; j < 3 ; j++)678if (regs[j] & (1 << 31))679regs[j] = 0;680681/* Byte 0 is level count, not a descriptor */682for (j = 1 ; j < 16 ; j++) {683unsigned char des = dp[j];684unsigned char k = 0;685686/* look up this descriptor in the table */687while (cache_table[k].descriptor != 0) {688if (cache_table[k].descriptor == des) {689if (only_trace && cache_table[k].cache_type != LVL_TRACE)690break;691switch (cache_table[k].cache_type) {692case LVL_1_INST:693l1i += cache_table[k].size;694break;695case LVL_1_DATA:696l1d += cache_table[k].size;697break;698case LVL_2:699l2 += cache_table[k].size;700break;701case LVL_3:702l3 += cache_table[k].size;703break;704case LVL_TRACE:705trace += cache_table[k].size;706break;707}708709break;710}711712k++;713}714}715}716}717718if (new_l1d)719l1d = new_l1d;720721if (new_l1i)722l1i = new_l1i;723724if (new_l2) {725l2 = new_l2;726#ifdef CONFIG_X86_HT727per_cpu(cpu_llc_id, cpu) = l2_id;728#endif729}730731if (new_l3) {732l3 = new_l3;733#ifdef CONFIG_X86_HT734per_cpu(cpu_llc_id, cpu) = l3_id;735#endif736}737738c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));739740return l2;741}742743#ifdef CONFIG_SYSFS744745/* pointer to _cpuid4_info array (for each cache leaf) */746static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);747#define CPUID4_INFO_IDX(x, y) (&((per_cpu(ici_cpuid4_info, x))[y]))748749#ifdef CONFIG_SMP750static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)751{752struct _cpuid4_info *this_leaf, *sibling_leaf;753unsigned long num_threads_sharing;754int index_msb, i, sibling;755struct cpuinfo_x86 *c = &cpu_data(cpu);756757if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {758for_each_cpu(i, cpu_llc_shared_mask(cpu)) {759if (!per_cpu(ici_cpuid4_info, i))760continue;761this_leaf = CPUID4_INFO_IDX(i, index);762for_each_cpu(sibling, cpu_llc_shared_mask(cpu)) {763if (!cpu_online(sibling))764continue;765set_bit(sibling, this_leaf->shared_cpu_map);766}767}768return;769}770this_leaf = CPUID4_INFO_IDX(cpu, index);771num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;772773if (num_threads_sharing == 1)774cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));775else {776index_msb = get_count_order(num_threads_sharing);777778for_each_online_cpu(i) {779if (cpu_data(i).apicid >> index_msb ==780c->apicid >> index_msb) {781cpumask_set_cpu(i,782to_cpumask(this_leaf->shared_cpu_map));783if (i != cpu && per_cpu(ici_cpuid4_info, i)) {784sibling_leaf =785CPUID4_INFO_IDX(i, index);786cpumask_set_cpu(cpu, to_cpumask(787sibling_leaf->shared_cpu_map));788}789}790}791}792}793static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)794{795struct _cpuid4_info *this_leaf, *sibling_leaf;796int sibling;797798this_leaf = CPUID4_INFO_IDX(cpu, index);799for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {800sibling_leaf = CPUID4_INFO_IDX(sibling, index);801cpumask_clear_cpu(cpu,802to_cpumask(sibling_leaf->shared_cpu_map));803}804}805#else806static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)807{808}809810static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)811{812}813#endif814815static void __cpuinit free_cache_attributes(unsigned int cpu)816{817int i;818819for (i = 0; i < num_cache_leaves; i++)820cache_remove_shared_cpu_map(cpu, i);821822kfree(per_cpu(ici_cpuid4_info, cpu)->l3);823kfree(per_cpu(ici_cpuid4_info, cpu));824per_cpu(ici_cpuid4_info, cpu) = NULL;825}826827static int828__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)829{830struct _cpuid4_info_regs *leaf_regs =831(struct _cpuid4_info_regs *)this_leaf;832833return cpuid4_cache_lookup_regs(index, leaf_regs);834}835836static void __cpuinit get_cpu_leaves(void *_retval)837{838int j, *retval = _retval, cpu = smp_processor_id();839840/* Do cpuid and store the results */841for (j = 0; j < num_cache_leaves; j++) {842struct _cpuid4_info *this_leaf;843this_leaf = CPUID4_INFO_IDX(cpu, j);844*retval = cpuid4_cache_lookup(j, this_leaf);845if (unlikely(*retval < 0)) {846int i;847848for (i = 0; i < j; i++)849cache_remove_shared_cpu_map(cpu, i);850break;851}852cache_shared_cpu_map_setup(cpu, j);853}854}855856static int __cpuinit detect_cache_attributes(unsigned int cpu)857{858int retval;859860if (num_cache_leaves == 0)861return -ENOENT;862863per_cpu(ici_cpuid4_info, cpu) = kzalloc(864sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);865if (per_cpu(ici_cpuid4_info, cpu) == NULL)866return -ENOMEM;867868smp_call_function_single(cpu, get_cpu_leaves, &retval, true);869if (retval) {870kfree(per_cpu(ici_cpuid4_info, cpu));871per_cpu(ici_cpuid4_info, cpu) = NULL;872}873874return retval;875}876877#include <linux/kobject.h>878#include <linux/sysfs.h>879880extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */881882/* pointer to kobject for cpuX/cache */883static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);884885struct _index_kobject {886struct kobject kobj;887unsigned int cpu;888unsigned short index;889};890891/* pointer to array of kobjects for cpuX/cache/indexY */892static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);893#define INDEX_KOBJECT_PTR(x, y) (&((per_cpu(ici_index_kobject, x))[y]))894895#define show_one_plus(file_name, object, val) \896static ssize_t show_##file_name(struct _cpuid4_info *this_leaf, char *buf, \897unsigned int cpu) \898{ \899return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \900}901902show_one_plus(level, eax.split.level, 0);903show_one_plus(coherency_line_size, ebx.split.coherency_line_size, 1);904show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);905show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);906show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);907908static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf,909unsigned int cpu)910{911return sprintf(buf, "%luK\n", this_leaf->size / 1024);912}913914static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,915int type, char *buf)916{917ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;918int n = 0;919920if (len > 1) {921const struct cpumask *mask;922923mask = to_cpumask(this_leaf->shared_cpu_map);924n = type ?925cpulist_scnprintf(buf, len-2, mask) :926cpumask_scnprintf(buf, len-2, mask);927buf[n++] = '\n';928buf[n] = '\0';929}930return n;931}932933static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf,934unsigned int cpu)935{936return show_shared_cpu_map_func(leaf, 0, buf);937}938939static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf,940unsigned int cpu)941{942return show_shared_cpu_map_func(leaf, 1, buf);943}944945static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf,946unsigned int cpu)947{948switch (this_leaf->eax.split.type) {949case CACHE_TYPE_DATA:950return sprintf(buf, "Data\n");951case CACHE_TYPE_INST:952return sprintf(buf, "Instruction\n");953case CACHE_TYPE_UNIFIED:954return sprintf(buf, "Unified\n");955default:956return sprintf(buf, "Unknown\n");957}958}959960#define to_object(k) container_of(k, struct _index_kobject, kobj)961#define to_attr(a) container_of(a, struct _cache_attr, attr)962963#define define_one_ro(_name) \964static struct _cache_attr _name = \965__ATTR(_name, 0444, show_##_name, NULL)966967define_one_ro(level);968define_one_ro(type);969define_one_ro(coherency_line_size);970define_one_ro(physical_line_partition);971define_one_ro(ways_of_associativity);972define_one_ro(number_of_sets);973define_one_ro(size);974define_one_ro(shared_cpu_map);975define_one_ro(shared_cpu_list);976977static struct attribute *default_attrs[] = {978&type.attr,979&level.attr,980&coherency_line_size.attr,981&physical_line_partition.attr,982&ways_of_associativity.attr,983&number_of_sets.attr,984&size.attr,985&shared_cpu_map.attr,986&shared_cpu_list.attr,987NULL988};989990#ifdef CONFIG_AMD_NB991static struct attribute ** __cpuinit amd_l3_attrs(void)992{993static struct attribute **attrs;994int n;995996if (attrs)997return attrs;998999n = sizeof (default_attrs) / sizeof (struct attribute *);10001001if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE))1002n += 2;10031004if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))1005n += 1;10061007attrs = kzalloc(n * sizeof (struct attribute *), GFP_KERNEL);1008if (attrs == NULL)1009return attrs = default_attrs;10101011for (n = 0; default_attrs[n]; n++)1012attrs[n] = default_attrs[n];10131014if (amd_nb_has_feature(AMD_NB_L3_INDEX_DISABLE)) {1015attrs[n++] = &cache_disable_0.attr;1016attrs[n++] = &cache_disable_1.attr;1017}10181019if (amd_nb_has_feature(AMD_NB_L3_PARTITIONING))1020attrs[n++] = &subcaches.attr;10211022return attrs;1023}1024#endif10251026static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)1027{1028struct _cache_attr *fattr = to_attr(attr);1029struct _index_kobject *this_leaf = to_object(kobj);1030ssize_t ret;10311032ret = fattr->show ?1033fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),1034buf, this_leaf->cpu) :10350;1036return ret;1037}10381039static ssize_t store(struct kobject *kobj, struct attribute *attr,1040const char *buf, size_t count)1041{1042struct _cache_attr *fattr = to_attr(attr);1043struct _index_kobject *this_leaf = to_object(kobj);1044ssize_t ret;10451046ret = fattr->store ?1047fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),1048buf, count, this_leaf->cpu) :10490;1050return ret;1051}10521053static const struct sysfs_ops sysfs_ops = {1054.show = show,1055.store = store,1056};10571058static struct kobj_type ktype_cache = {1059.sysfs_ops = &sysfs_ops,1060.default_attrs = default_attrs,1061};10621063static struct kobj_type ktype_percpu_entry = {1064.sysfs_ops = &sysfs_ops,1065};10661067static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu)1068{1069kfree(per_cpu(ici_cache_kobject, cpu));1070kfree(per_cpu(ici_index_kobject, cpu));1071per_cpu(ici_cache_kobject, cpu) = NULL;1072per_cpu(ici_index_kobject, cpu) = NULL;1073free_cache_attributes(cpu);1074}10751076static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)1077{1078int err;10791080if (num_cache_leaves == 0)1081return -ENOENT;10821083err = detect_cache_attributes(cpu);1084if (err)1085return err;10861087/* Allocate all required memory */1088per_cpu(ici_cache_kobject, cpu) =1089kzalloc(sizeof(struct kobject), GFP_KERNEL);1090if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))1091goto err_out;10921093per_cpu(ici_index_kobject, cpu) = kzalloc(1094sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);1095if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))1096goto err_out;10971098return 0;10991100err_out:1101cpuid4_cache_sysfs_exit(cpu);1102return -ENOMEM;1103}11041105static DECLARE_BITMAP(cache_dev_map, NR_CPUS);11061107/* Add/Remove cache interface for CPU device */1108static int __cpuinit cache_add_dev(struct sys_device * sys_dev)1109{1110unsigned int cpu = sys_dev->id;1111unsigned long i, j;1112struct _index_kobject *this_object;1113struct _cpuid4_info *this_leaf;1114int retval;11151116retval = cpuid4_cache_sysfs_init(cpu);1117if (unlikely(retval < 0))1118return retval;11191120retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),1121&ktype_percpu_entry,1122&sys_dev->kobj, "%s", "cache");1123if (retval < 0) {1124cpuid4_cache_sysfs_exit(cpu);1125return retval;1126}11271128for (i = 0; i < num_cache_leaves; i++) {1129this_object = INDEX_KOBJECT_PTR(cpu, i);1130this_object->cpu = cpu;1131this_object->index = i;11321133this_leaf = CPUID4_INFO_IDX(cpu, i);11341135ktype_cache.default_attrs = default_attrs;1136#ifdef CONFIG_AMD_NB1137if (this_leaf->l3)1138ktype_cache.default_attrs = amd_l3_attrs();1139#endif1140retval = kobject_init_and_add(&(this_object->kobj),1141&ktype_cache,1142per_cpu(ici_cache_kobject, cpu),1143"index%1lu", i);1144if (unlikely(retval)) {1145for (j = 0; j < i; j++)1146kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));1147kobject_put(per_cpu(ici_cache_kobject, cpu));1148cpuid4_cache_sysfs_exit(cpu);1149return retval;1150}1151kobject_uevent(&(this_object->kobj), KOBJ_ADD);1152}1153cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));11541155kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);1156return 0;1157}11581159static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)1160{1161unsigned int cpu = sys_dev->id;1162unsigned long i;11631164if (per_cpu(ici_cpuid4_info, cpu) == NULL)1165return;1166if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))1167return;1168cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));11691170for (i = 0; i < num_cache_leaves; i++)1171kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));1172kobject_put(per_cpu(ici_cache_kobject, cpu));1173cpuid4_cache_sysfs_exit(cpu);1174}11751176static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,1177unsigned long action, void *hcpu)1178{1179unsigned int cpu = (unsigned long)hcpu;1180struct sys_device *sys_dev;11811182sys_dev = get_cpu_sysdev(cpu);1183switch (action) {1184case CPU_ONLINE:1185case CPU_ONLINE_FROZEN:1186cache_add_dev(sys_dev);1187break;1188case CPU_DEAD:1189case CPU_DEAD_FROZEN:1190cache_remove_dev(sys_dev);1191break;1192}1193return NOTIFY_OK;1194}11951196static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = {1197.notifier_call = cacheinfo_cpu_callback,1198};11991200static int __cpuinit cache_sysfs_init(void)1201{1202int i;12031204if (num_cache_leaves == 0)1205return 0;12061207for_each_online_cpu(i) {1208int err;1209struct sys_device *sys_dev = get_cpu_sysdev(i);12101211err = cache_add_dev(sys_dev);1212if (err)1213return err;1214}1215register_hotcpu_notifier(&cacheinfo_cpu_notifier);1216return 0;1217}12181219device_initcall(cache_sysfs_init);12201221#endif122212231224