intel_cacheinfo.c 28.6 KB
Newer Older
L
Linus Torvalds 已提交
1
/*
2
 *	Routines to indentify caches on Intel CPU.
L
Linus Torvalds 已提交
3
 *
4 5
 *	Changes:
 *	Venkatesh Pallipadi	: Adding cache identification through cpuid(4)
A
Alan Cox 已提交
6
 *	Ashok Raj <ashok.raj@intel.com>: Work with CPU hotplug infrastructure.
7
 *	Andi Kleen / Andreas Herrmann	: CPUID4 emulation on AMD.
L
Linus Torvalds 已提交
8 9 10 11 12 13 14
 */

#include <linux/init.h>
#include <linux/slab.h>
#include <linux/device.h>
#include <linux/compiler.h>
#include <linux/cpu.h>
T
Tim Schmielau 已提交
15
#include <linux/sched.h>
16
#include <linux/pci.h>
L
Linus Torvalds 已提交
17 18

#include <asm/processor.h>
A
Alan Cox 已提交
19
#include <linux/smp.h>
20
#include <asm/k8.h>
21
#include <asm/smp.h>
L
Linus Torvalds 已提交
22 23 24 25 26 27 28

#define LVL_1_INST	1
#define LVL_1_DATA	2
#define LVL_2		3
#define LVL_3		4
#define LVL_TRACE	5

A
Alan Cox 已提交
29
struct _cache_table {
L
Linus Torvalds 已提交
30 31 32 33 34
	unsigned char descriptor;
	char cache_type;
	short size;
};

A
Alan Cox 已提交
35 36 37
/* All the cache descriptor types we care about (no TLB or
   trace cache entries) */

38
static const struct _cache_table __cpuinitconst cache_table[] =
L
Linus Torvalds 已提交
39 40 41
{
	{ 0x06, LVL_1_INST, 8 },	/* 4-way set assoc, 32 byte line size */
	{ 0x08, LVL_1_INST, 16 },	/* 4-way set assoc, 32 byte line size */
42
	{ 0x09, LVL_1_INST, 32 },	/* 4-way set assoc, 64 byte line size */
L
Linus Torvalds 已提交
43 44
	{ 0x0a, LVL_1_DATA, 8 },	/* 2 way set assoc, 32 byte line size */
	{ 0x0c, LVL_1_DATA, 16 },	/* 4-way set assoc, 32 byte line size */
45 46
	{ 0x0d, LVL_1_DATA, 16 },	/* 4-way set assoc, 64 byte line size */
	{ 0x21, LVL_2,      256 },	/* 8-way set assoc, 64 byte line size */
L
Linus Torvalds 已提交
47 48 49 50 51 52 53
	{ 0x22, LVL_3,      512 },	/* 4-way set assoc, sectored cache, 64 byte line size */
	{ 0x23, LVL_3,      1024 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x25, LVL_3,      2048 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x29, LVL_3,      4096 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x2c, LVL_1_DATA, 32 },	/* 8-way set assoc, 64 byte line size */
	{ 0x30, LVL_1_INST, 32 },	/* 8-way set assoc, 64 byte line size */
	{ 0x39, LVL_2,      128 },	/* 4-way set assoc, sectored cache, 64 byte line size */
54
	{ 0x3a, LVL_2,      192 },	/* 6-way set assoc, sectored cache, 64 byte line size */
L
Linus Torvalds 已提交
55 56
	{ 0x3b, LVL_2,      128 },	/* 2-way set assoc, sectored cache, 64 byte line size */
	{ 0x3c, LVL_2,      256 },	/* 4-way set assoc, sectored cache, 64 byte line size */
57 58
	{ 0x3d, LVL_2,      384 },	/* 6-way set assoc, sectored cache, 64 byte line size */
	{ 0x3e, LVL_2,      512 },	/* 4-way set assoc, sectored cache, 64 byte line size */
59
	{ 0x3f, LVL_2,      256 },	/* 2-way set assoc, 64 byte line size */
L
Linus Torvalds 已提交
60 61 62 63 64
	{ 0x41, LVL_2,      128 },	/* 4-way set assoc, 32 byte line size */
	{ 0x42, LVL_2,      256 },	/* 4-way set assoc, 32 byte line size */
	{ 0x43, LVL_2,      512 },	/* 4-way set assoc, 32 byte line size */
	{ 0x44, LVL_2,      1024 },	/* 4-way set assoc, 32 byte line size */
	{ 0x45, LVL_2,      2048 },	/* 4-way set assoc, 32 byte line size */
65 66 67 68 69 70 71
	{ 0x46, LVL_3,      4096 },	/* 4-way set assoc, 64 byte line size */
	{ 0x47, LVL_3,      8192 },	/* 8-way set assoc, 64 byte line size */
	{ 0x49, LVL_3,      4096 },	/* 16-way set assoc, 64 byte line size */
	{ 0x4a, LVL_3,      6144 },	/* 12-way set assoc, 64 byte line size */
	{ 0x4b, LVL_3,      8192 },	/* 16-way set assoc, 64 byte line size */
	{ 0x4c, LVL_3,     12288 },	/* 12-way set assoc, 64 byte line size */
	{ 0x4d, LVL_3,     16384 },	/* 16-way set assoc, 64 byte line size */
D
Dave Jones 已提交
72
	{ 0x4e, LVL_2,      6144 },	/* 24-way set assoc, 64 byte line size */
L
Linus Torvalds 已提交
73 74 75 76 77 78 79
	{ 0x60, LVL_1_DATA, 16 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x66, LVL_1_DATA, 8 },	/* 4-way set assoc, sectored cache, 64 byte line size */
	{ 0x67, LVL_1_DATA, 16 },	/* 4-way set assoc, sectored cache, 64 byte line size */
	{ 0x68, LVL_1_DATA, 32 },	/* 4-way set assoc, sectored cache, 64 byte line size */
	{ 0x70, LVL_TRACE,  12 },	/* 8-way set assoc */
	{ 0x71, LVL_TRACE,  16 },	/* 8-way set assoc */
	{ 0x72, LVL_TRACE,  32 },	/* 8-way set assoc */
80
	{ 0x73, LVL_TRACE,  64 },	/* 8-way set assoc */
L
Linus Torvalds 已提交
81 82 83 84 85 86 87 88 89 90 91 92 93
	{ 0x78, LVL_2,    1024 },	/* 4-way set assoc, 64 byte line size */
	{ 0x79, LVL_2,     128 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x7a, LVL_2,     256 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x7b, LVL_2,     512 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x7c, LVL_2,    1024 },	/* 8-way set assoc, sectored cache, 64 byte line size */
	{ 0x7d, LVL_2,    2048 },	/* 8-way set assoc, 64 byte line size */
	{ 0x7f, LVL_2,     512 },	/* 2-way set assoc, 64 byte line size */
	{ 0x82, LVL_2,     256 },	/* 8-way set assoc, 32 byte line size */
	{ 0x83, LVL_2,     512 },	/* 8-way set assoc, 32 byte line size */
	{ 0x84, LVL_2,    1024 },	/* 8-way set assoc, 32 byte line size */
	{ 0x85, LVL_2,    2048 },	/* 8-way set assoc, 32 byte line size */
	{ 0x86, LVL_2,     512 },	/* 4-way set assoc, 64 byte line size */
	{ 0x87, LVL_2,    1024 },	/* 8-way set assoc, 64 byte line size */
94 95 96 97
	{ 0xd0, LVL_3,     512 },	/* 4-way set assoc, 64 byte line size */
	{ 0xd1, LVL_3,    1024 },	/* 4-way set assoc, 64 byte line size */
	{ 0xd2, LVL_3,    2048 },	/* 4-way set assoc, 64 byte line size */
	{ 0xd6, LVL_3,    1024 },	/* 8-way set assoc, 64 byte line size */
98
	{ 0xd7, LVL_3,    2048 },	/* 8-way set assoc, 64 byte line size */
99 100 101 102 103 104 105
	{ 0xd8, LVL_3,    4096 },	/* 12-way set assoc, 64 byte line size */
	{ 0xdc, LVL_3,    2048 },	/* 12-way set assoc, 64 byte line size */
	{ 0xdd, LVL_3,    4096 },	/* 12-way set assoc, 64 byte line size */
	{ 0xde, LVL_3,    8192 },	/* 12-way set assoc, 64 byte line size */
	{ 0xe2, LVL_3,    2048 },	/* 16-way set assoc, 64 byte line size */
	{ 0xe3, LVL_3,    4096 },	/* 16-way set assoc, 64 byte line size */
	{ 0xe4, LVL_3,    8192 },	/* 16-way set assoc, 64 byte line size */
106 107 108
	{ 0xea, LVL_3,    12288 },	/* 24-way set assoc, 64 byte line size */
	{ 0xeb, LVL_3,    18432 },	/* 24-way set assoc, 64 byte line size */
	{ 0xec, LVL_3,    24576 },	/* 24-way set assoc, 64 byte line size */
L
Linus Torvalds 已提交
109 110 111 112
	{ 0x00, 0, 0}
};


A
Alan Cox 已提交
113
enum _cache_type {
L
Linus Torvalds 已提交
114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153
	CACHE_TYPE_NULL	= 0,
	CACHE_TYPE_DATA = 1,
	CACHE_TYPE_INST = 2,
	CACHE_TYPE_UNIFIED = 3
};

union _cpuid4_leaf_eax {
	struct {
		enum _cache_type	type:5;
		unsigned int		level:3;
		unsigned int		is_self_initializing:1;
		unsigned int		is_fully_associative:1;
		unsigned int		reserved:4;
		unsigned int		num_threads_sharing:12;
		unsigned int		num_cores_on_die:6;
	} split;
	u32 full;
};

union _cpuid4_leaf_ebx {
	struct {
		unsigned int		coherency_line_size:12;
		unsigned int		physical_line_partition:10;
		unsigned int		ways_of_associativity:10;
	} split;
	u32 full;
};

union _cpuid4_leaf_ecx {
	struct {
		unsigned int		number_of_sets:32;
	} split;
	u32 full;
};

struct _cpuid4_info {
	union _cpuid4_leaf_eax eax;
	union _cpuid4_leaf_ebx ebx;
	union _cpuid4_leaf_ecx ecx;
	unsigned long size;
154 155
	bool can_disable;
	unsigned int l3_indices;
156 157 158 159 160 161 162 163 164
	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
};

/* subset of above _cpuid4_info w/o shared_cpu_map */
struct _cpuid4_info_regs {
	union _cpuid4_leaf_eax eax;
	union _cpuid4_leaf_ebx ebx;
	union _cpuid4_leaf_ecx ecx;
	unsigned long size;
165 166
	bool can_disable;
	unsigned int l3_indices;
L
Linus Torvalds 已提交
167 168
};

169 170 171 172
unsigned short			num_cache_leaves;

/* AMD doesn't have CPUID4. Emulate it here to report the same
   information to the user.  This makes some assumptions about the machine:
173
   L2 not shared, no SMT etc. that is currently true on AMD CPUs.
174 175 176 177 178

   In theory the TLBs could be reported as fake type (they are in "dummy").
   Maybe later */
union l1_cache {
	struct {
A
Alan Cox 已提交
179 180 181 182
		unsigned line_size:8;
		unsigned lines_per_tag:8;
		unsigned assoc:8;
		unsigned size_in_kb:8;
183 184 185 186 187 188
	};
	unsigned val;
};

union l2_cache {
	struct {
A
Alan Cox 已提交
189 190 191 192
		unsigned line_size:8;
		unsigned lines_per_tag:4;
		unsigned assoc:4;
		unsigned size_in_kb:16;
193 194 195 196
	};
	unsigned val;
};

197 198
union l3_cache {
	struct {
A
Alan Cox 已提交
199 200 201 202 203
		unsigned line_size:8;
		unsigned lines_per_tag:4;
		unsigned assoc:4;
		unsigned res:2;
		unsigned size_encoded:14;
204 205 206 207
	};
	unsigned val;
};

208
static const unsigned short __cpuinitconst assocs[] = {
209 210 211 212 213 214 215
	[1] = 1,
	[2] = 2,
	[4] = 4,
	[6] = 8,
	[8] = 16,
	[0xa] = 32,
	[0xb] = 48,
216
	[0xc] = 64,
217 218 219
	[0xd] = 96,
	[0xe] = 128,
	[0xf] = 0xffff /* fully associative - no way to show this currently */
220 221
};

222 223
static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 };
static const unsigned char __cpuinitconst types[] = { 1, 2, 3, 3 };
224

225 226 227 228
static void __cpuinit
amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
		     union _cpuid4_leaf_ebx *ebx,
		     union _cpuid4_leaf_ecx *ecx)
229 230 231 232 233
{
	unsigned dummy;
	unsigned line_size, lines_per_tag, assoc, size_in_kb;
	union l1_cache l1i, l1d;
	union l2_cache l2;
234 235
	union l3_cache l3;
	union l1_cache *l1 = &l1d;
236 237 238 239 240 241

	eax->full = 0;
	ebx->full = 0;
	ecx->full = 0;

	cpuid(0x80000005, &dummy, &dummy, &l1d.val, &l1i.val);
242
	cpuid(0x80000006, &dummy, &dummy, &l2.val, &l3.val);
243

244 245 246 247 248 249
	switch (leaf) {
	case 1:
		l1 = &l1i;
	case 0:
		if (!l1->val)
			return;
250
		assoc = assocs[l1->assoc];
251 252 253
		line_size = l1->line_size;
		lines_per_tag = l1->lines_per_tag;
		size_in_kb = l1->size_in_kb;
254 255 256 257
		break;
	case 2:
		if (!l2.val)
			return;
258
		assoc = assocs[l2.assoc];
259 260 261 262
		line_size = l2.line_size;
		lines_per_tag = l2.lines_per_tag;
		/* cpu_data has errata corrections for K7 applied */
		size_in_kb = current_cpu_data.x86_cache_size;
263 264 265 266
		break;
	case 3:
		if (!l3.val)
			return;
267
		assoc = assocs[l3.assoc];
268 269 270
		line_size = l3.line_size;
		lines_per_tag = l3.lines_per_tag;
		size_in_kb = l3.size_encoded * 512;
271 272 273 274
		if (boot_cpu_has(X86_FEATURE_AMD_DCM)) {
			size_in_kb = size_in_kb >> 1;
			assoc = assoc >> 1;
		}
275 276 277
		break;
	default:
		return;
278 279
	}

280 281 282
	eax->split.is_self_initializing = 1;
	eax->split.type = types[leaf];
	eax->split.level = levels[leaf];
283
	eax->split.num_threads_sharing = 0;
284 285 286
	eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1;


287
	if (assoc == 0xffff)
288 289
		eax->split.is_fully_associative = 1;
	ebx->split.coherency_line_size = line_size - 1;
290
	ebx->split.ways_of_associativity = assoc - 1;
291 292 293 294
	ebx->split.physical_line_partition = lines_per_tag - 1;
	ecx->split.number_of_sets = (size_in_kb * 1024) / line_size /
		(ebx->split.ways_of_associativity + 1) - 1;
}
L
Linus Torvalds 已提交
295

296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318
static unsigned int __cpuinit amd_calc_l3_indices(void)
{
	/*
	 * We're called over smp_call_function_single() and therefore
	 * are on the correct cpu.
	 */
	int cpu = smp_processor_id();
	int node = cpu_to_node(cpu);
	struct pci_dev *dev = node_to_k8_nb_misc(node);
	unsigned int sc0, sc1, sc2, sc3;
	u32 val;

	pci_read_config_dword(dev, 0x1C4, &val);

	/* calculate subcache sizes */
	sc0 = !(val & BIT(0));
	sc1 = !(val & BIT(4));
	sc2 = !(val & BIT(8))  + !(val & BIT(9));
	sc3 = !(val & BIT(12)) + !(val & BIT(13));

	return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
}

319
static void __cpuinit
320
amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
321 322 323
{
	if (index < 3)
		return;
324 325 326 327

	if (boot_cpu_data.x86 == 0x11)
		return;

328 329
	/* see errata #382 and #388 */
	if ((boot_cpu_data.x86 == 0x10) &&
330
	    ((boot_cpu_data.x86_model < 0x8) ||
331
	     (boot_cpu_data.x86_mask  < 0x1)))
332 333
		return;

334 335
	this_leaf->can_disable = true;
	this_leaf->l3_indices  = amd_calc_l3_indices();
336 337
}

338
static int
339 340
__cpuinit cpuid4_cache_lookup_regs(int index,
				   struct _cpuid4_info_regs *this_leaf)
L
Linus Torvalds 已提交
341
{
342 343 344 345
	union _cpuid4_leaf_eax 	eax;
	union _cpuid4_leaf_ebx 	ebx;
	union _cpuid4_leaf_ecx 	ecx;
	unsigned		edx;
L
Linus Torvalds 已提交
346

347
	if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) {
348
		amd_cpuid4(index, &eax, &ebx, &ecx);
349 350
		if (boot_cpu_data.x86 >= 0x10)
			amd_check_l3_disable(index, this_leaf);
351 352 353 354
	} else {
		cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
	}

355
	if (eax.split.type == CACHE_TYPE_NULL)
356
		return -EIO; /* better error ? */
L
Linus Torvalds 已提交
357

358 359 360
	this_leaf->eax = eax;
	this_leaf->ebx = ebx;
	this_leaf->ecx = ecx;
361 362 363 364
	this_leaf->size = (ecx.split.number_of_sets          + 1) *
			  (ebx.split.coherency_line_size     + 1) *
			  (ebx.split.physical_line_partition + 1) *
			  (ebx.split.ways_of_associativity   + 1);
L
Linus Torvalds 已提交
365 366 367
	return 0;
}

368
static int __cpuinit find_num_cache_leaves(void)
L
Linus Torvalds 已提交
369 370 371
{
	unsigned int		eax, ebx, ecx, edx;
	union _cpuid4_leaf_eax	cache_eax;
372
	int 			i = -1;
L
Linus Torvalds 已提交
373

374 375 376
	do {
		++i;
		/* Do cpuid(4) loop to find out num_cache_leaves */
L
Linus Torvalds 已提交
377 378
		cpuid_count(4, i, &eax, &ebx, &ecx, &edx);
		cache_eax.full = eax;
379 380
	} while (cache_eax.split.type != CACHE_TYPE_NULL);
	return i;
L
Linus Torvalds 已提交
381 382
}

383
unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c)
L
Linus Torvalds 已提交
384
{
A
Alan Cox 已提交
385 386
	/* Cache sizes */
	unsigned int trace = 0, l1i = 0, l1d = 0, l2 = 0, l3 = 0;
L
Linus Torvalds 已提交
387 388
	unsigned int new_l1d = 0, new_l1i = 0; /* Cache sizes from cpuid(4) */
	unsigned int new_l2 = 0, new_l3 = 0, i; /* Cache sizes from cpuid(4) */
389
	unsigned int l2_id = 0, l3_id = 0, num_threads_sharing, index_msb;
390
#ifdef CONFIG_X86_HT
391
	unsigned int cpu = c->cpu_index;
392
#endif
L
Linus Torvalds 已提交
393

394
	if (c->cpuid_level > 3) {
L
Linus Torvalds 已提交
395 396 397 398 399 400 401 402 403 404 405 406 407
		static int is_initialized;

		if (is_initialized == 0) {
			/* Init num_cache_leaves from boot CPU */
			num_cache_leaves = find_num_cache_leaves();
			is_initialized++;
		}

		/*
		 * Whenever possible use cpuid(4), deterministic cache
		 * parameters cpuid leaf to find the cache details
		 */
		for (i = 0; i < num_cache_leaves; i++) {
408
			struct _cpuid4_info_regs this_leaf;
L
Linus Torvalds 已提交
409 410
			int retval;

411
			retval = cpuid4_cache_lookup_regs(i, &this_leaf);
L
Linus Torvalds 已提交
412
			if (retval >= 0) {
A
Alan Cox 已提交
413 414
				switch (this_leaf.eax.split.level) {
				case 1:
L
Linus Torvalds 已提交
415 416 417 418 419 420 421
					if (this_leaf.eax.split.type ==
							CACHE_TYPE_DATA)
						new_l1d = this_leaf.size/1024;
					else if (this_leaf.eax.split.type ==
							CACHE_TYPE_INST)
						new_l1i = this_leaf.size/1024;
					break;
A
Alan Cox 已提交
422
				case 2:
L
Linus Torvalds 已提交
423
					new_l2 = this_leaf.size/1024;
424 425 426
					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
					index_msb = get_count_order(num_threads_sharing);
					l2_id = c->apicid >> index_msb;
L
Linus Torvalds 已提交
427
					break;
A
Alan Cox 已提交
428
				case 3:
L
Linus Torvalds 已提交
429
					new_l3 = this_leaf.size/1024;
430
					num_threads_sharing = 1 + this_leaf.eax.split.num_threads_sharing;
A
Alan Cox 已提交
431 432
					index_msb = get_count_order(
							num_threads_sharing);
433
					l3_id = c->apicid >> index_msb;
L
Linus Torvalds 已提交
434
					break;
A
Alan Cox 已提交
435
				default:
L
Linus Torvalds 已提交
436 437 438 439 440
					break;
				}
			}
		}
	}
441 442 443 444 445
	/*
	 * Don't use cpuid2 if cpuid4 is supported. For P4, we use cpuid2 for
	 * trace cache
	 */
	if ((num_cache_leaves == 0 || c->x86 == 15) && c->cpuid_level > 1) {
L
Linus Torvalds 已提交
446
		/* supports eax=2  call */
447 448
		int j, n;
		unsigned int regs[4];
L
Linus Torvalds 已提交
449
		unsigned char *dp = (unsigned char *)regs;
450 451 452 453
		int only_trace = 0;

		if (num_cache_leaves != 0 && c->x86 == 15)
			only_trace = 1;
L
Linus Torvalds 已提交
454 455 456 457

		/* Number of times to iterate */
		n = cpuid_eax(2) & 0xFF;

A
Alan Cox 已提交
458
		for (i = 0 ; i < n ; i++) {
L
Linus Torvalds 已提交
459 460 461
			cpuid(2, &regs[0], &regs[1], &regs[2], &regs[3]);

			/* If bit 31 is set, this is an unknown format */
A
Alan Cox 已提交
462 463 464
			for (j = 0 ; j < 3 ; j++)
				if (regs[j] & (1 << 31))
					regs[j] = 0;
L
Linus Torvalds 已提交
465 466

			/* Byte 0 is level count, not a descriptor */
A
Alan Cox 已提交
467
			for (j = 1 ; j < 16 ; j++) {
L
Linus Torvalds 已提交
468 469 470 471
				unsigned char des = dp[j];
				unsigned char k = 0;

				/* look up this descriptor in the table */
A
Alan Cox 已提交
472
				while (cache_table[k].descriptor != 0) {
L
Linus Torvalds 已提交
473
					if (cache_table[k].descriptor == des) {
474 475
						if (only_trace && cache_table[k].cache_type != LVL_TRACE)
							break;
L
Linus Torvalds 已提交
476 477 478 479 480 481 482 483 484 485 486 487 488 489 490 491 492 493 494 495 496 497 498 499 500
						switch (cache_table[k].cache_type) {
						case LVL_1_INST:
							l1i += cache_table[k].size;
							break;
						case LVL_1_DATA:
							l1d += cache_table[k].size;
							break;
						case LVL_2:
							l2 += cache_table[k].size;
							break;
						case LVL_3:
							l3 += cache_table[k].size;
							break;
						case LVL_TRACE:
							trace += cache_table[k].size;
							break;
						}

						break;
					}

					k++;
				}
			}
		}
501
	}
L
Linus Torvalds 已提交
502

503 504
	if (new_l1d)
		l1d = new_l1d;
L
Linus Torvalds 已提交
505

506 507
	if (new_l1i)
		l1i = new_l1i;
L
Linus Torvalds 已提交
508

509 510
	if (new_l2) {
		l2 = new_l2;
511
#ifdef CONFIG_X86_HT
512
		per_cpu(cpu_llc_id, cpu) = l2_id;
513
#endif
514
	}
L
Linus Torvalds 已提交
515

516 517
	if (new_l3) {
		l3 = new_l3;
518
#ifdef CONFIG_X86_HT
519
		per_cpu(cpu_llc_id, cpu) = l3_id;
520
#endif
L
Linus Torvalds 已提交
521 522
	}

523 524
	c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d));

L
Linus Torvalds 已提交
525 526 527
	return l2;
}

528 529
#ifdef CONFIG_SYSFS

L
Linus Torvalds 已提交
530
/* pointer to _cpuid4_info array (for each cache leaf) */
531 532
static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info);
#define CPUID4_INFO_IDX(x, y)	(&((per_cpu(ici_cpuid4_info, x))[y]))
L
Linus Torvalds 已提交
533 534

#ifdef CONFIG_SMP
535
static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
L
Linus Torvalds 已提交
536
{
537
	struct _cpuid4_info	*this_leaf, *sibling_leaf;
L
Linus Torvalds 已提交
538
	unsigned long num_threads_sharing;
539
	int index_msb, i, sibling;
540
	struct cpuinfo_x86 *c = &cpu_data(cpu);
L
Linus Torvalds 已提交
541

542
	if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) {
543
		for_each_cpu(i, c->llc_shared_map) {
544
			if (!per_cpu(ici_cpuid4_info, i))
545 546
				continue;
			this_leaf = CPUID4_INFO_IDX(i, index);
547 548 549 550 551
			for_each_cpu(sibling, c->llc_shared_map) {
				if (!cpu_online(sibling))
					continue;
				set_bit(sibling, this_leaf->shared_cpu_map);
			}
552 553 554
		}
		return;
	}
L
Linus Torvalds 已提交
555 556 557 558
	this_leaf = CPUID4_INFO_IDX(cpu, index);
	num_threads_sharing = 1 + this_leaf->eax.split.num_threads_sharing;

	if (num_threads_sharing == 1)
559
		cpumask_set_cpu(cpu, to_cpumask(this_leaf->shared_cpu_map));
560 561 562 563
	else {
		index_msb = get_count_order(num_threads_sharing);

		for_each_online_cpu(i) {
564 565
			if (cpu_data(i).apicid >> index_msb ==
			    c->apicid >> index_msb) {
566 567
				cpumask_set_cpu(i,
					to_cpumask(this_leaf->shared_cpu_map));
568
				if (i != cpu && per_cpu(ici_cpuid4_info, i))  {
569 570 571 572
					sibling_leaf =
						CPUID4_INFO_IDX(i, index);
					cpumask_set_cpu(cpu, to_cpumask(
						sibling_leaf->shared_cpu_map));
573 574 575 576 577
				}
			}
		}
	}
}
578
static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
579 580 581 582 583
{
	struct _cpuid4_info	*this_leaf, *sibling_leaf;
	int sibling;

	this_leaf = CPUID4_INFO_IDX(cpu, index);
584
	for_each_cpu(sibling, to_cpumask(this_leaf->shared_cpu_map)) {
585
		sibling_leaf = CPUID4_INFO_IDX(sibling, index);
586 587
		cpumask_clear_cpu(cpu,
				  to_cpumask(sibling_leaf->shared_cpu_map));
588
	}
L
Linus Torvalds 已提交
589 590
}
#else
A
Alan Cox 已提交
591 592 593 594 595 596 597
static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index)
{
}

static void __cpuinit cache_remove_shared_cpu_map(unsigned int cpu, int index)
{
}
L
Linus Torvalds 已提交
598 599
#endif

600
static void __cpuinit free_cache_attributes(unsigned int cpu)
L
Linus Torvalds 已提交
601
{
602 603 604 605 606
	int i;

	for (i = 0; i < num_cache_leaves; i++)
		cache_remove_shared_cpu_map(cpu, i);

607 608
	kfree(per_cpu(ici_cpuid4_info, cpu));
	per_cpu(ici_cpuid4_info, cpu) = NULL;
L
Linus Torvalds 已提交
609 610
}

611 612 613 614 615 616 617 618 619
static int
__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
{
	struct _cpuid4_info_regs *leaf_regs =
		(struct _cpuid4_info_regs *)this_leaf;

	return cpuid4_cache_lookup_regs(index, leaf_regs);
}

620
static void __cpuinit get_cpu_leaves(void *_retval)
L
Linus Torvalds 已提交
621
{
622
	int j, *retval = _retval, cpu = smp_processor_id();
623

L
Linus Torvalds 已提交
624 625
	/* Do cpuid and store the results */
	for (j = 0; j < num_cache_leaves; j++) {
626
		struct _cpuid4_info *this_leaf;
L
Linus Torvalds 已提交
627
		this_leaf = CPUID4_INFO_IDX(cpu, j);
628 629
		*retval = cpuid4_cache_lookup(j, this_leaf);
		if (unlikely(*retval < 0)) {
630 631 632 633
			int i;

			for (i = 0; i < j; i++)
				cache_remove_shared_cpu_map(cpu, i);
634
			break;
635
		}
L
Linus Torvalds 已提交
636 637
		cache_shared_cpu_map_setup(cpu, j);
	}
638 639 640 641 642 643 644 645 646
}

static int __cpuinit detect_cache_attributes(unsigned int cpu)
{
	int			retval;

	if (num_cache_leaves == 0)
		return -ENOENT;

647
	per_cpu(ici_cpuid4_info, cpu) = kzalloc(
648
	    sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL);
649
	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
650
		return -ENOMEM;
L
Linus Torvalds 已提交
651

652
	smp_call_function_single(cpu, get_cpu_leaves, &retval, true);
653
	if (retval) {
654 655
		kfree(per_cpu(ici_cpuid4_info, cpu));
		per_cpu(ici_cpuid4_info, cpu) = NULL;
656 657
	}

658
	return retval;
L
Linus Torvalds 已提交
659 660 661 662 663 664 665 666
}

#include <linux/kobject.h>
#include <linux/sysfs.h>

extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */

/* pointer to kobject for cpuX/cache */
667
static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject);
L
Linus Torvalds 已提交
668 669 670 671 672 673 674 675

struct _index_kobject {
	struct kobject kobj;
	unsigned int cpu;
	unsigned short index;
};

/* pointer to array of kobjects for cpuX/cache/indexY */
676 677
static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject);
#define INDEX_KOBJECT_PTR(x, y)		(&((per_cpu(ici_index_kobject, x))[y]))
L
Linus Torvalds 已提交
678 679 680 681 682

#define show_one_plus(file_name, object, val)				\
static ssize_t show_##file_name						\
			(struct _cpuid4_info *this_leaf, char *buf)	\
{									\
A
Alan Cox 已提交
683
	return sprintf(buf, "%lu\n", (unsigned long)this_leaf->object + val); \
L
Linus Torvalds 已提交
684 685 686 687 688 689 690 691 692 693
}

show_one_plus(level, eax.split.level, 0);
show_one_plus(coherency_line_size, ebx.split.coherency_line_size, 1);
show_one_plus(physical_line_partition, ebx.split.physical_line_partition, 1);
show_one_plus(ways_of_associativity, ebx.split.ways_of_associativity, 1);
show_one_plus(number_of_sets, ecx.split.number_of_sets, 1);

static ssize_t show_size(struct _cpuid4_info *this_leaf, char *buf)
{
A
Alan Cox 已提交
694
	return sprintf(buf, "%luK\n", this_leaf->size / 1024);
L
Linus Torvalds 已提交
695 696
}

697 698
static ssize_t show_shared_cpu_map_func(struct _cpuid4_info *this_leaf,
					int type, char *buf)
L
Linus Torvalds 已提交
699
{
700
	ptrdiff_t len = PTR_ALIGN(buf + PAGE_SIZE - 1, PAGE_SIZE) - buf;
701 702
	int n = 0;

703
	if (len > 1) {
704
		const struct cpumask *mask;
705

706
		mask = to_cpumask(this_leaf->shared_cpu_map);
A
Alan Cox 已提交
707
		n = type ?
708 709
			cpulist_scnprintf(buf, len-2, mask) :
			cpumask_scnprintf(buf, len-2, mask);
710 711
		buf[n++] = '\n';
		buf[n] = '\0';
712 713
	}
	return n;
L
Linus Torvalds 已提交
714 715
}

716 717 718 719 720 721 722 723 724 725
static inline ssize_t show_shared_cpu_map(struct _cpuid4_info *leaf, char *buf)
{
	return show_shared_cpu_map_func(leaf, 0, buf);
}

static inline ssize_t show_shared_cpu_list(struct _cpuid4_info *leaf, char *buf)
{
	return show_shared_cpu_map_func(leaf, 1, buf);
}

726 727 728 729
static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf)
{
	switch (this_leaf->eax.split.type) {
	case CACHE_TYPE_DATA:
L
Linus Torvalds 已提交
730
		return sprintf(buf, "Data\n");
731
	case CACHE_TYPE_INST:
L
Linus Torvalds 已提交
732
		return sprintf(buf, "Instruction\n");
733
	case CACHE_TYPE_UNIFIED:
L
Linus Torvalds 已提交
734
		return sprintf(buf, "Unified\n");
735
	default:
L
Linus Torvalds 已提交
736 737 738 739
		return sprintf(buf, "Unknown\n");
	}
}

740 741
#define to_object(k)	container_of(k, struct _index_kobject, kobj)
#define to_attr(a)	container_of(a, struct _cache_attr, attr)
742

743 744
static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
				  unsigned int index)
745
{
746
	int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
747
	int node = amd_get_nb_id(cpu);
748 749
	struct pci_dev *dev = node_to_k8_nb_misc(node);
	unsigned int reg = 0;
750

751
	if (!this_leaf->can_disable)
752 753
		return -EINVAL;

754 755
	if (!dev)
		return -EINVAL;
756

757
	pci_read_config_dword(dev, 0x1BC + index * 4, &reg);
758
	return sprintf(buf, "0x%08x\n", reg);
759
}
760

761 762
#define SHOW_CACHE_DISABLE(index)					\
static ssize_t								\
763
show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf)	\
764 765
{									\
	return show_cache_disable(this_leaf, buf, index);		\
766
}
767 768
SHOW_CACHE_DISABLE(0)
SHOW_CACHE_DISABLE(1)
769

770 771
static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
	const char *buf, size_t count, unsigned int index)
772
{
773
	int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map));
774
	int node = amd_get_nb_id(cpu);
775 776
	struct pci_dev *dev = node_to_k8_nb_misc(node);
	unsigned long val = 0;
777 778 779

#define SUBCACHE_MASK	(3UL << 20)
#define SUBCACHE_INDEX	0xfff
780 781

	if (!this_leaf->can_disable)
782
		return -EINVAL;
783

784 785
	if (!capable(CAP_SYS_ADMIN))
		return -EPERM;
786

787
	if (!dev)
788 789
		return -EINVAL;

790
	if (strict_strtoul(buf, 10, &val) < 0)
791
		return -EINVAL;
792

793
	/* do not allow writes outside of allowed bits */
794 795
	if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
	    ((val & SUBCACHE_INDEX) > this_leaf->l3_indices))
796
		return -EINVAL;
797

798
	val |= BIT(30);
799
	pci_write_config_dword(dev, 0x1BC + index * 4, val);
800 801 802 803 804 805
	/*
	 * We need to WBINVD on a core on the node containing the L3 cache which
	 * indices we disable therefore a simple wbinvd() is not sufficient.
	 */
	wbinvd_on_cpu(cpu);
	pci_write_config_dword(dev, 0x1BC + index * 4, val | BIT(31));
806 807
	return count;
}
808

809 810
#define STORE_CACHE_DISABLE(index)					\
static ssize_t								\
811
store_cache_disable_##index(struct _cpuid4_info *this_leaf,		\
812 813 814
			    const char *buf, size_t count)		\
{									\
	return store_cache_disable(this_leaf, buf, count, index);	\
815
}
816 817
STORE_CACHE_DISABLE(0)
STORE_CACHE_DISABLE(1)
818

L
Linus Torvalds 已提交
819 820 821 822 823 824 825 826 827 828 829 830 831 832 833 834 835 836
struct _cache_attr {
	struct attribute attr;
	ssize_t (*show)(struct _cpuid4_info *, char *);
	ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count);
};

#define define_one_ro(_name) \
static struct _cache_attr _name = \
	__ATTR(_name, 0444, show_##_name, NULL)

define_one_ro(level);
define_one_ro(type);
define_one_ro(coherency_line_size);
define_one_ro(physical_line_partition);
define_one_ro(ways_of_associativity);
define_one_ro(number_of_sets);
define_one_ro(size);
define_one_ro(shared_cpu_map);
837
define_one_ro(shared_cpu_list);
L
Linus Torvalds 已提交
838

839 840 841 842
static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
		show_cache_disable_0, store_cache_disable_0);
static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
		show_cache_disable_1, store_cache_disable_1);
843

844 845 846 847 848 849 850 851 852 853 854
#define DEFAULT_SYSFS_CACHE_ATTRS	\
	&type.attr,			\
	&level.attr,			\
	&coherency_line_size.attr,	\
	&physical_line_partition.attr,	\
	&ways_of_associativity.attr,	\
	&number_of_sets.attr,		\
	&size.attr,			\
	&shared_cpu_map.attr,		\
	&shared_cpu_list.attr

A
Alan Cox 已提交
855
static struct attribute *default_attrs[] = {
856 857 858 859 860 861
	DEFAULT_SYSFS_CACHE_ATTRS,
	NULL
};

static struct attribute *default_l3_attrs[] = {
	DEFAULT_SYSFS_CACHE_ATTRS,
862 863
	&cache_disable_0.attr,
	&cache_disable_1.attr,
L
Linus Torvalds 已提交
864 865 866
	NULL
};

A
Alan Cox 已提交
867
static ssize_t show(struct kobject *kobj, struct attribute *attr, char *buf)
L
Linus Torvalds 已提交
868 869 870 871 872 873 874 875
{
	struct _cache_attr *fattr = to_attr(attr);
	struct _index_kobject *this_leaf = to_object(kobj);
	ssize_t ret;

	ret = fattr->show ?
		fattr->show(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
			buf) :
876
		0;
L
Linus Torvalds 已提交
877 878 879
	return ret;
}

A
Alan Cox 已提交
880 881
static ssize_t store(struct kobject *kobj, struct attribute *attr,
		     const char *buf, size_t count)
L
Linus Torvalds 已提交
882
{
883 884 885 886
	struct _cache_attr *fattr = to_attr(attr);
	struct _index_kobject *this_leaf = to_object(kobj);
	ssize_t ret;

887 888 889
	ret = fattr->store ?
		fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index),
			buf, count) :
890 891
		0;
	return ret;
L
Linus Torvalds 已提交
892 893 894 895 896 897 898 899 900 901 902 903 904 905 906 907
}

static struct sysfs_ops sysfs_ops = {
	.show   = show,
	.store  = store,
};

static struct kobj_type ktype_cache = {
	.sysfs_ops	= &sysfs_ops,
	.default_attrs	= default_attrs,
};

static struct kobj_type ktype_percpu_entry = {
	.sysfs_ops	= &sysfs_ops,
};

908
static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu)
L
Linus Torvalds 已提交
909
{
910 911 912 913
	kfree(per_cpu(ici_cache_kobject, cpu));
	kfree(per_cpu(ici_index_kobject, cpu));
	per_cpu(ici_cache_kobject, cpu) = NULL;
	per_cpu(ici_index_kobject, cpu) = NULL;
L
Linus Torvalds 已提交
914 915 916
	free_cache_attributes(cpu);
}

917
static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu)
L
Linus Torvalds 已提交
918
{
919
	int err;
L
Linus Torvalds 已提交
920 921 922 923

	if (num_cache_leaves == 0)
		return -ENOENT;

924 925 926
	err = detect_cache_attributes(cpu);
	if (err)
		return err;
L
Linus Torvalds 已提交
927 928

	/* Allocate all required memory */
929
	per_cpu(ici_cache_kobject, cpu) =
930
		kzalloc(sizeof(struct kobject), GFP_KERNEL);
931
	if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL))
L
Linus Torvalds 已提交
932 933
		goto err_out;

934
	per_cpu(ici_index_kobject, cpu) = kzalloc(
A
Alan Cox 已提交
935
	    sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL);
936
	if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL))
L
Linus Torvalds 已提交
937 938 939 940 941 942 943 944 945
		goto err_out;

	return 0;

err_out:
	cpuid4_cache_sysfs_exit(cpu);
	return -ENOMEM;
}

946
static DECLARE_BITMAP(cache_dev_map, NR_CPUS);
947

L
Linus Torvalds 已提交
948
/* Add/Remove cache interface for CPU device */
949
static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
L
Linus Torvalds 已提交
950 951 952 953
{
	unsigned int cpu = sys_dev->id;
	unsigned long i, j;
	struct _index_kobject *this_object;
954
	struct _cpuid4_info   *this_leaf;
955
	int retval;
L
Linus Torvalds 已提交
956 957 958 959 960

	retval = cpuid4_cache_sysfs_init(cpu);
	if (unlikely(retval < 0))
		return retval;

961
	retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu),
962
				      &ktype_percpu_entry,
963
				      &sys_dev->kobj, "%s", "cache");
964 965 966 967
	if (retval < 0) {
		cpuid4_cache_sysfs_exit(cpu);
		return retval;
	}
L
Linus Torvalds 已提交
968 969

	for (i = 0; i < num_cache_leaves; i++) {
A
Alan Cox 已提交
970
		this_object = INDEX_KOBJECT_PTR(cpu, i);
L
Linus Torvalds 已提交
971 972
		this_object->cpu = cpu;
		this_object->index = i;
973 974 975 976 977 978 979 980

		this_leaf = CPUID4_INFO_IDX(cpu, i);

		if (this_leaf->can_disable)
			ktype_cache.default_attrs = default_l3_attrs;
		else
			ktype_cache.default_attrs = default_attrs;

981
		retval = kobject_init_and_add(&(this_object->kobj),
982
					      &ktype_cache,
983
					      per_cpu(ici_cache_kobject, cpu),
984
					      "index%1lu", i);
L
Linus Torvalds 已提交
985
		if (unlikely(retval)) {
A
Alan Cox 已提交
986 987
			for (j = 0; j < i; j++)
				kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj));
988
			kobject_put(per_cpu(ici_cache_kobject, cpu));
L
Linus Torvalds 已提交
989
			cpuid4_cache_sysfs_exit(cpu);
990
			return retval;
L
Linus Torvalds 已提交
991
		}
992
		kobject_uevent(&(this_object->kobj), KOBJ_ADD);
L
Linus Torvalds 已提交
993
	}
994
	cpumask_set_cpu(cpu, to_cpumask(cache_dev_map));
995

996
	kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD);
997
	return 0;
L
Linus Torvalds 已提交
998 999
}

1000
static void __cpuinit cache_remove_dev(struct sys_device * sys_dev)
L
Linus Torvalds 已提交
1001 1002 1003 1004
{
	unsigned int cpu = sys_dev->id;
	unsigned long i;

1005
	if (per_cpu(ici_cpuid4_info, cpu) == NULL)
1006
		return;
1007
	if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map)))
1008
		return;
1009
	cpumask_clear_cpu(cpu, to_cpumask(cache_dev_map));
1010 1011

	for (i = 0; i < num_cache_leaves; i++)
A
Alan Cox 已提交
1012
		kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj));
1013
	kobject_put(per_cpu(ici_cache_kobject, cpu));
L
Linus Torvalds 已提交
1014
	cpuid4_cache_sysfs_exit(cpu);
1015 1016
}

1017
static int __cpuinit cacheinfo_cpu_callback(struct notifier_block *nfb,
1018 1019 1020 1021 1022 1023 1024 1025
					unsigned long action, void *hcpu)
{
	unsigned int cpu = (unsigned long)hcpu;
	struct sys_device *sys_dev;

	sys_dev = get_cpu_sysdev(cpu);
	switch (action) {
	case CPU_ONLINE:
1026
	case CPU_ONLINE_FROZEN:
1027 1028 1029
		cache_add_dev(sys_dev);
		break;
	case CPU_DEAD:
1030
	case CPU_DEAD_FROZEN:
1031 1032 1033 1034
		cache_remove_dev(sys_dev);
		break;
	}
	return NOTIFY_OK;
L
Linus Torvalds 已提交
1035 1036
}

A
Alan Cox 已提交
1037
static struct notifier_block __cpuinitdata cacheinfo_cpu_notifier = {
1038
	.notifier_call = cacheinfo_cpu_callback,
L
Linus Torvalds 已提交
1039 1040
};

1041
static int __cpuinit cache_sysfs_init(void)
L
Linus Torvalds 已提交
1042
{
1043 1044
	int i;

L
Linus Torvalds 已提交
1045 1046 1047
	if (num_cache_leaves == 0)
		return 0;

1048
	for_each_online_cpu(i) {
1049 1050
		int err;
		struct sys_device *sys_dev = get_cpu_sysdev(i);
1051

1052 1053 1054
		err = cache_add_dev(sys_dev);
		if (err)
			return err;
1055
	}
1056
	register_hotcpu_notifier(&cacheinfo_cpu_notifier);
1057
	return 0;
L
Linus Torvalds 已提交
1058 1059
}

1060
device_initcall(cache_sysfs_init);
L
Linus Torvalds 已提交
1061 1062

#endif