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