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