diff options
author | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
---|---|---|
committer | Andrea Bastoni <bastoni@cs.unc.edu> | 2010-05-30 19:16:45 -0400 |
commit | ada47b5fe13d89735805b566185f4885f5a3f750 (patch) | |
tree | 644b88f8a71896307d71438e9b3af49126ffb22b /arch/x86/kernel/cpu/intel_cacheinfo.c | |
parent | 43e98717ad40a4ae64545b5ba047c7b86aa44f4f (diff) | |
parent | 3280f21d43ee541f97f8cda5792150d2dbec20d5 (diff) |
Merge branch 'wip-2.6.34' into old-private-masterarchived-private-master
Diffstat (limited to 'arch/x86/kernel/cpu/intel_cacheinfo.c')
-rw-r--r-- | arch/x86/kernel/cpu/intel_cacheinfo.c | 420 |
1 files changed, 238 insertions, 182 deletions
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 3167c3d72596..94d8e475744c 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c | |||
@@ -18,6 +18,7 @@ | |||
18 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
19 | #include <linux/smp.h> | 19 | #include <linux/smp.h> |
20 | #include <asm/k8.h> | 20 | #include <asm/k8.h> |
21 | #include <asm/smp.h> | ||
21 | 22 | ||
22 | #define LVL_1_INST 1 | 23 | #define LVL_1_INST 1 |
23 | #define LVL_1_DATA 2 | 24 | #define LVL_1_DATA 2 |
@@ -31,6 +32,8 @@ struct _cache_table { | |||
31 | short size; | 32 | short size; |
32 | }; | 33 | }; |
33 | 34 | ||
35 | #define MB(x) ((x) * 1024) | ||
36 | |||
34 | /* All the cache descriptor types we care about (no TLB or | 37 | /* All the cache descriptor types we care about (no TLB or |
35 | trace cache entries) */ | 38 | trace cache entries) */ |
36 | 39 | ||
@@ -44,9 +47,9 @@ static const struct _cache_table __cpuinitconst cache_table[] = | |||
44 | { 0x0d, LVL_1_DATA, 16 }, /* 4-way set assoc, 64 byte line size */ | 47 | { 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 */ | 48 | { 0x21, LVL_2, 256 }, /* 8-way set assoc, 64 byte line size */ |
46 | { 0x22, LVL_3, 512 }, /* 4-way set assoc, sectored cache, 64 byte line size */ | 49 | { 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 */ | 50 | { 0x23, LVL_3, MB(1) }, /* 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 */ | 51 | { 0x25, LVL_3, MB(2) }, /* 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 */ | 52 | { 0x29, LVL_3, MB(4) }, /* 8-way set assoc, sectored cache, 64 byte line size */ |
50 | { 0x2c, LVL_1_DATA, 32 }, /* 8-way set assoc, 64 byte line size */ | 53 | { 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 */ | 54 | { 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 */ | 55 | { 0x39, LVL_2, 128 }, /* 4-way set assoc, sectored cache, 64 byte line size */ |
@@ -59,16 +62,16 @@ static const struct _cache_table __cpuinitconst cache_table[] = | |||
59 | { 0x41, LVL_2, 128 }, /* 4-way set assoc, 32 byte line size */ | 62 | { 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 */ | 63 | { 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 */ | 64 | { 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 */ | 65 | { 0x44, LVL_2, MB(1) }, /* 4-way set assoc, 32 byte line size */ |
63 | { 0x45, LVL_2, 2048 }, /* 4-way set assoc, 32 byte line size */ | 66 | { 0x45, LVL_2, MB(2) }, /* 4-way set assoc, 32 byte line size */ |
64 | { 0x46, LVL_3, 4096 }, /* 4-way set assoc, 64 byte line size */ | 67 | { 0x46, LVL_3, MB(4) }, /* 4-way set assoc, 64 byte line size */ |
65 | { 0x47, LVL_3, 8192 }, /* 8-way set assoc, 64 byte line size */ | 68 | { 0x47, LVL_3, MB(8) }, /* 8-way set assoc, 64 byte line size */ |
66 | { 0x49, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */ | 69 | { 0x49, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */ |
67 | { 0x4a, LVL_3, 6144 }, /* 12-way set assoc, 64 byte line size */ | 70 | { 0x4a, LVL_3, MB(6) }, /* 12-way set assoc, 64 byte line size */ |
68 | { 0x4b, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */ | 71 | { 0x4b, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */ |
69 | { 0x4c, LVL_3, 12288 }, /* 12-way set assoc, 64 byte line size */ | 72 | { 0x4c, LVL_3, MB(12) }, /* 12-way set assoc, 64 byte line size */ |
70 | { 0x4d, LVL_3, 16384 }, /* 16-way set assoc, 64 byte line size */ | 73 | { 0x4d, LVL_3, MB(16) }, /* 16-way set assoc, 64 byte line size */ |
71 | { 0x4e, LVL_2, 6144 }, /* 24-way set assoc, 64 byte line size */ | 74 | { 0x4e, LVL_2, MB(6) }, /* 24-way set assoc, 64 byte line size */ |
72 | { 0x60, LVL_1_DATA, 16 }, /* 8-way set assoc, sectored cache, 64 byte line size */ | 75 | { 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 */ | 76 | { 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 */ | 77 | { 0x67, LVL_1_DATA, 16 }, /* 4-way set assoc, sectored cache, 64 byte line size */ |
@@ -77,31 +80,34 @@ static const struct _cache_table __cpuinitconst cache_table[] = | |||
77 | { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */ | 80 | { 0x71, LVL_TRACE, 16 }, /* 8-way set assoc */ |
78 | { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */ | 81 | { 0x72, LVL_TRACE, 32 }, /* 8-way set assoc */ |
79 | { 0x73, LVL_TRACE, 64 }, /* 8-way set assoc */ | 82 | { 0x73, LVL_TRACE, 64 }, /* 8-way set assoc */ |
80 | { 0x78, LVL_2, 1024 }, /* 4-way set assoc, 64 byte line size */ | 83 | { 0x78, LVL_2, MB(1) }, /* 4-way set assoc, 64 byte line size */ |
81 | { 0x79, LVL_2, 128 }, /* 8-way set assoc, sectored cache, 64 byte line size */ | 84 | { 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 */ | 85 | { 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 */ | 86 | { 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 */ | 87 | { 0x7c, LVL_2, MB(1) }, /* 8-way set assoc, sectored cache, 64 byte line size */ |
85 | { 0x7d, LVL_2, 2048 }, /* 8-way set assoc, 64 byte line size */ | 88 | { 0x7d, LVL_2, MB(2) }, /* 8-way set assoc, 64 byte line size */ |
86 | { 0x7f, LVL_2, 512 }, /* 2-way set assoc, 64 byte line size */ | 89 | { 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 */ | 90 | { 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 */ | 91 | { 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 */ | 92 | { 0x84, LVL_2, MB(1) }, /* 8-way set assoc, 32 byte line size */ |
90 | { 0x85, LVL_2, 2048 }, /* 8-way set assoc, 32 byte line size */ | 93 | { 0x85, LVL_2, MB(2) }, /* 8-way set assoc, 32 byte line size */ |
91 | { 0x86, LVL_2, 512 }, /* 4-way set assoc, 64 byte line size */ | 94 | { 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 */ | 95 | { 0x87, LVL_2, MB(1) }, /* 8-way set assoc, 64 byte line size */ |
93 | { 0xd0, LVL_3, 512 }, /* 4-way set assoc, 64 byte line size */ | 96 | { 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 */ | 97 | { 0xd1, LVL_3, MB(1) }, /* 4-way set assoc, 64 byte line size */ |
95 | { 0xd2, LVL_3, 2048 }, /* 4-way set assoc, 64 byte line size */ | 98 | { 0xd2, LVL_3, MB(2) }, /* 4-way set assoc, 64 byte line size */ |
96 | { 0xd6, LVL_3, 1024 }, /* 8-way set assoc, 64 byte line size */ | 99 | { 0xd6, LVL_3, MB(1) }, /* 8-way set assoc, 64 byte line size */ |
97 | { 0xd7, LVL_3, 2038 }, /* 8-way set assoc, 64 byte line size */ | 100 | { 0xd7, LVL_3, MB(2) }, /* 8-way set assoc, 64 byte line size */ |
98 | { 0xd8, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ | 101 | { 0xd8, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */ |
99 | { 0xdc, LVL_3, 2048 }, /* 12-way set assoc, 64 byte line size */ | 102 | { 0xdc, LVL_3, MB(2) }, /* 12-way set assoc, 64 byte line size */ |
100 | { 0xdd, LVL_3, 4096 }, /* 12-way set assoc, 64 byte line size */ | 103 | { 0xdd, LVL_3, MB(4) }, /* 12-way set assoc, 64 byte line size */ |
101 | { 0xde, LVL_3, 8192 }, /* 12-way set assoc, 64 byte line size */ | 104 | { 0xde, LVL_3, MB(8) }, /* 12-way set assoc, 64 byte line size */ |
102 | { 0xe2, LVL_3, 2048 }, /* 16-way set assoc, 64 byte line size */ | 105 | { 0xe2, LVL_3, MB(2) }, /* 16-way set assoc, 64 byte line size */ |
103 | { 0xe3, LVL_3, 4096 }, /* 16-way set assoc, 64 byte line size */ | 106 | { 0xe3, LVL_3, MB(4) }, /* 16-way set assoc, 64 byte line size */ |
104 | { 0xe4, LVL_3, 8192 }, /* 16-way set assoc, 64 byte line size */ | 107 | { 0xe4, LVL_3, MB(8) }, /* 16-way set assoc, 64 byte line size */ |
108 | { 0xea, LVL_3, MB(12) }, /* 24-way set assoc, 64 byte line size */ | ||
109 | { 0xeb, LVL_3, MB(18) }, /* 24-way set assoc, 64 byte line size */ | ||
110 | { 0xec, LVL_3, MB(24) }, /* 24-way set assoc, 64 byte line size */ | ||
105 | { 0x00, 0, 0} | 111 | { 0x00, 0, 0} |
106 | }; | 112 | }; |
107 | 113 | ||
@@ -147,7 +153,8 @@ struct _cpuid4_info { | |||
147 | union _cpuid4_leaf_ebx ebx; | 153 | union _cpuid4_leaf_ebx ebx; |
148 | union _cpuid4_leaf_ecx ecx; | 154 | union _cpuid4_leaf_ecx ecx; |
149 | unsigned long size; | 155 | unsigned long size; |
150 | unsigned long can_disable; | 156 | bool can_disable; |
157 | unsigned int l3_indices; | ||
151 | DECLARE_BITMAP(shared_cpu_map, NR_CPUS); | 158 | DECLARE_BITMAP(shared_cpu_map, NR_CPUS); |
152 | }; | 159 | }; |
153 | 160 | ||
@@ -157,7 +164,8 @@ struct _cpuid4_info_regs { | |||
157 | union _cpuid4_leaf_ebx ebx; | 164 | union _cpuid4_leaf_ebx ebx; |
158 | union _cpuid4_leaf_ecx ecx; | 165 | union _cpuid4_leaf_ecx ecx; |
159 | unsigned long size; | 166 | unsigned long size; |
160 | unsigned long can_disable; | 167 | bool can_disable; |
168 | unsigned int l3_indices; | ||
161 | }; | 169 | }; |
162 | 170 | ||
163 | unsigned short num_cache_leaves; | 171 | unsigned short num_cache_leaves; |
@@ -287,6 +295,36 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, | |||
287 | (ebx->split.ways_of_associativity + 1) - 1; | 295 | (ebx->split.ways_of_associativity + 1) - 1; |
288 | } | 296 | } |
289 | 297 | ||
298 | struct _cache_attr { | ||
299 | struct attribute attr; | ||
300 | ssize_t (*show)(struct _cpuid4_info *, char *); | ||
301 | ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count); | ||
302 | }; | ||
303 | |||
304 | #ifdef CONFIG_CPU_SUP_AMD | ||
305 | static unsigned int __cpuinit amd_calc_l3_indices(void) | ||
306 | { | ||
307 | /* | ||
308 | * We're called over smp_call_function_single() and therefore | ||
309 | * are on the correct cpu. | ||
310 | */ | ||
311 | int cpu = smp_processor_id(); | ||
312 | int node = cpu_to_node(cpu); | ||
313 | struct pci_dev *dev = node_to_k8_nb_misc(node); | ||
314 | unsigned int sc0, sc1, sc2, sc3; | ||
315 | u32 val = 0; | ||
316 | |||
317 | pci_read_config_dword(dev, 0x1C4, &val); | ||
318 | |||
319 | /* calculate subcache sizes */ | ||
320 | sc0 = !(val & BIT(0)); | ||
321 | sc1 = !(val & BIT(4)); | ||
322 | sc2 = !(val & BIT(8)) + !(val & BIT(9)); | ||
323 | sc3 = !(val & BIT(12)) + !(val & BIT(13)); | ||
324 | |||
325 | return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1; | ||
326 | } | ||
327 | |||
290 | static void __cpuinit | 328 | static void __cpuinit |
291 | amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) | 329 | amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) |
292 | { | 330 | { |
@@ -296,13 +334,108 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) | |||
296 | if (boot_cpu_data.x86 == 0x11) | 334 | if (boot_cpu_data.x86 == 0x11) |
297 | return; | 335 | return; |
298 | 336 | ||
299 | /* see erratum #382 */ | 337 | /* see errata #382 and #388 */ |
300 | if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) | 338 | if ((boot_cpu_data.x86 == 0x10) && |
339 | ((boot_cpu_data.x86_model < 0x8) || | ||
340 | (boot_cpu_data.x86_mask < 0x1))) | ||
301 | return; | 341 | return; |
302 | 342 | ||
303 | this_leaf->can_disable = 1; | 343 | /* not in virtualized environments */ |
344 | if (num_k8_northbridges == 0) | ||
345 | return; | ||
346 | |||
347 | this_leaf->can_disable = true; | ||
348 | this_leaf->l3_indices = amd_calc_l3_indices(); | ||
349 | } | ||
350 | |||
351 | static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, | ||
352 | unsigned int index) | ||
353 | { | ||
354 | int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); | ||
355 | int node = amd_get_nb_id(cpu); | ||
356 | struct pci_dev *dev = node_to_k8_nb_misc(node); | ||
357 | unsigned int reg = 0; | ||
358 | |||
359 | if (!this_leaf->can_disable) | ||
360 | return -EINVAL; | ||
361 | |||
362 | if (!dev) | ||
363 | return -EINVAL; | ||
364 | |||
365 | pci_read_config_dword(dev, 0x1BC + index * 4, ®); | ||
366 | return sprintf(buf, "0x%08x\n", reg); | ||
304 | } | 367 | } |
305 | 368 | ||
369 | #define SHOW_CACHE_DISABLE(index) \ | ||
370 | static ssize_t \ | ||
371 | show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ | ||
372 | { \ | ||
373 | return show_cache_disable(this_leaf, buf, index); \ | ||
374 | } | ||
375 | SHOW_CACHE_DISABLE(0) | ||
376 | SHOW_CACHE_DISABLE(1) | ||
377 | |||
378 | static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, | ||
379 | const char *buf, size_t count, unsigned int index) | ||
380 | { | ||
381 | int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); | ||
382 | int node = amd_get_nb_id(cpu); | ||
383 | struct pci_dev *dev = node_to_k8_nb_misc(node); | ||
384 | unsigned long val = 0; | ||
385 | |||
386 | #define SUBCACHE_MASK (3UL << 20) | ||
387 | #define SUBCACHE_INDEX 0xfff | ||
388 | |||
389 | if (!this_leaf->can_disable) | ||
390 | return -EINVAL; | ||
391 | |||
392 | if (!capable(CAP_SYS_ADMIN)) | ||
393 | return -EPERM; | ||
394 | |||
395 | if (!dev) | ||
396 | return -EINVAL; | ||
397 | |||
398 | if (strict_strtoul(buf, 10, &val) < 0) | ||
399 | return -EINVAL; | ||
400 | |||
401 | /* do not allow writes outside of allowed bits */ | ||
402 | if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) || | ||
403 | ((val & SUBCACHE_INDEX) > this_leaf->l3_indices)) | ||
404 | return -EINVAL; | ||
405 | |||
406 | val |= BIT(30); | ||
407 | pci_write_config_dword(dev, 0x1BC + index * 4, val); | ||
408 | /* | ||
409 | * We need to WBINVD on a core on the node containing the L3 cache which | ||
410 | * indices we disable therefore a simple wbinvd() is not sufficient. | ||
411 | */ | ||
412 | wbinvd_on_cpu(cpu); | ||
413 | pci_write_config_dword(dev, 0x1BC + index * 4, val | BIT(31)); | ||
414 | return count; | ||
415 | } | ||
416 | |||
417 | #define STORE_CACHE_DISABLE(index) \ | ||
418 | static ssize_t \ | ||
419 | store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ | ||
420 | const char *buf, size_t count) \ | ||
421 | { \ | ||
422 | return store_cache_disable(this_leaf, buf, count, index); \ | ||
423 | } | ||
424 | STORE_CACHE_DISABLE(0) | ||
425 | STORE_CACHE_DISABLE(1) | ||
426 | |||
427 | static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, | ||
428 | show_cache_disable_0, store_cache_disable_0); | ||
429 | static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, | ||
430 | show_cache_disable_1, store_cache_disable_1); | ||
431 | |||
432 | #else /* CONFIG_CPU_SUP_AMD */ | ||
433 | static void __cpuinit | ||
434 | amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) | ||
435 | { | ||
436 | }; | ||
437 | #endif /* CONFIG_CPU_SUP_AMD */ | ||
438 | |||
306 | static int | 439 | static int |
307 | __cpuinit cpuid4_cache_lookup_regs(int index, | 440 | __cpuinit cpuid4_cache_lookup_regs(int index, |
308 | struct _cpuid4_info_regs *this_leaf) | 441 | struct _cpuid4_info_regs *this_leaf) |
@@ -488,22 +621,6 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
488 | #endif | 621 | #endif |
489 | } | 622 | } |
490 | 623 | ||
491 | if (trace) | ||
492 | printk(KERN_INFO "CPU: Trace cache: %dK uops", trace); | ||
493 | else if (l1i) | ||
494 | printk(KERN_INFO "CPU: L1 I cache: %dK", l1i); | ||
495 | |||
496 | if (l1d) | ||
497 | printk(KERN_CONT ", L1 D cache: %dK\n", l1d); | ||
498 | else | ||
499 | printk(KERN_CONT "\n"); | ||
500 | |||
501 | if (l2) | ||
502 | printk(KERN_INFO "CPU: L2 cache: %dK\n", l2); | ||
503 | |||
504 | if (l3) | ||
505 | printk(KERN_INFO "CPU: L3 cache: %dK\n", l3); | ||
506 | |||
507 | c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); | 624 | c->x86_cache_size = l3 ? l3 : (l2 ? l2 : (l1i+l1d)); |
508 | 625 | ||
509 | return l2; | 626 | return l2; |
@@ -512,8 +629,8 @@ unsigned int __cpuinit init_intel_cacheinfo(struct cpuinfo_x86 *c) | |||
512 | #ifdef CONFIG_SYSFS | 629 | #ifdef CONFIG_SYSFS |
513 | 630 | ||
514 | /* pointer to _cpuid4_info array (for each cache leaf) */ | 631 | /* pointer to _cpuid4_info array (for each cache leaf) */ |
515 | static DEFINE_PER_CPU(struct _cpuid4_info *, cpuid4_info); | 632 | static DEFINE_PER_CPU(struct _cpuid4_info *, ici_cpuid4_info); |
516 | #define CPUID4_INFO_IDX(x, y) (&((per_cpu(cpuid4_info, x))[y])) | 633 | #define CPUID4_INFO_IDX(x, y) (&((per_cpu(ici_cpuid4_info, x))[y])) |
517 | 634 | ||
518 | /* returns CPUs that share the index cache with cpu */ | 635 | /* returns CPUs that share the index cache with cpu */ |
519 | int get_shared_cpu_map(cpumask_var_t mask, unsigned int cpu, int index) | 636 | int get_shared_cpu_map(cpumask_var_t mask, unsigned int cpu, int index) |
@@ -537,18 +654,19 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) | |||
537 | { | 654 | { |
538 | struct _cpuid4_info *this_leaf, *sibling_leaf; | 655 | struct _cpuid4_info *this_leaf, *sibling_leaf; |
539 | unsigned long num_threads_sharing; | 656 | unsigned long num_threads_sharing; |
540 | int index_msb, i; | 657 | int index_msb, i, sibling; |
541 | struct cpuinfo_x86 *c = &cpu_data(cpu); | 658 | struct cpuinfo_x86 *c = &cpu_data(cpu); |
542 | 659 | ||
543 | if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) { | 660 | if ((index == 3) && (c->x86_vendor == X86_VENDOR_AMD)) { |
544 | struct cpuinfo_x86 *d; | 661 | for_each_cpu(i, c->llc_shared_map) { |
545 | for_each_online_cpu(i) { | 662 | if (!per_cpu(ici_cpuid4_info, i)) |
546 | if (!per_cpu(cpuid4_info, i)) | ||
547 | continue; | 663 | continue; |
548 | d = &cpu_data(i); | ||
549 | this_leaf = CPUID4_INFO_IDX(i, index); | 664 | this_leaf = CPUID4_INFO_IDX(i, index); |
550 | cpumask_copy(to_cpumask(this_leaf->shared_cpu_map), | 665 | for_each_cpu(sibling, c->llc_shared_map) { |
551 | d->llc_shared_map); | 666 | if (!cpu_online(sibling)) |
667 | continue; | ||
668 | set_bit(sibling, this_leaf->shared_cpu_map); | ||
669 | } | ||
552 | } | 670 | } |
553 | return; | 671 | return; |
554 | } | 672 | } |
@@ -565,7 +683,7 @@ static void __cpuinit cache_shared_cpu_map_setup(unsigned int cpu, int index) | |||
565 | c->apicid >> index_msb) { | 683 | c->apicid >> index_msb) { |
566 | cpumask_set_cpu(i, | 684 | cpumask_set_cpu(i, |
567 | to_cpumask(this_leaf->shared_cpu_map)); | 685 | to_cpumask(this_leaf->shared_cpu_map)); |
568 | if (i != cpu && per_cpu(cpuid4_info, i)) { | 686 | if (i != cpu && per_cpu(ici_cpuid4_info, i)) { |
569 | sibling_leaf = | 687 | sibling_leaf = |
570 | CPUID4_INFO_IDX(i, index); | 688 | CPUID4_INFO_IDX(i, index); |
571 | cpumask_set_cpu(cpu, to_cpumask( | 689 | cpumask_set_cpu(cpu, to_cpumask( |
@@ -604,8 +722,8 @@ static void __cpuinit free_cache_attributes(unsigned int cpu) | |||
604 | for (i = 0; i < num_cache_leaves; i++) | 722 | for (i = 0; i < num_cache_leaves; i++) |
605 | cache_remove_shared_cpu_map(cpu, i); | 723 | cache_remove_shared_cpu_map(cpu, i); |
606 | 724 | ||
607 | kfree(per_cpu(cpuid4_info, cpu)); | 725 | kfree(per_cpu(ici_cpuid4_info, cpu)); |
608 | per_cpu(cpuid4_info, cpu) = NULL; | 726 | per_cpu(ici_cpuid4_info, cpu) = NULL; |
609 | } | 727 | } |
610 | 728 | ||
611 | static int | 729 | static int |
@@ -644,15 +762,15 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu) | |||
644 | if (num_cache_leaves == 0) | 762 | if (num_cache_leaves == 0) |
645 | return -ENOENT; | 763 | return -ENOENT; |
646 | 764 | ||
647 | per_cpu(cpuid4_info, cpu) = kzalloc( | 765 | per_cpu(ici_cpuid4_info, cpu) = kzalloc( |
648 | sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL); | 766 | sizeof(struct _cpuid4_info) * num_cache_leaves, GFP_KERNEL); |
649 | if (per_cpu(cpuid4_info, cpu) == NULL) | 767 | if (per_cpu(ici_cpuid4_info, cpu) == NULL) |
650 | return -ENOMEM; | 768 | return -ENOMEM; |
651 | 769 | ||
652 | smp_call_function_single(cpu, get_cpu_leaves, &retval, true); | 770 | smp_call_function_single(cpu, get_cpu_leaves, &retval, true); |
653 | if (retval) { | 771 | if (retval) { |
654 | kfree(per_cpu(cpuid4_info, cpu)); | 772 | kfree(per_cpu(ici_cpuid4_info, cpu)); |
655 | per_cpu(cpuid4_info, cpu) = NULL; | 773 | per_cpu(ici_cpuid4_info, cpu) = NULL; |
656 | } | 774 | } |
657 | 775 | ||
658 | return retval; | 776 | return retval; |
@@ -664,7 +782,7 @@ static int __cpuinit detect_cache_attributes(unsigned int cpu) | |||
664 | extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */ | 782 | extern struct sysdev_class cpu_sysdev_class; /* from drivers/base/cpu.c */ |
665 | 783 | ||
666 | /* pointer to kobject for cpuX/cache */ | 784 | /* pointer to kobject for cpuX/cache */ |
667 | static DEFINE_PER_CPU(struct kobject *, cache_kobject); | 785 | static DEFINE_PER_CPU(struct kobject *, ici_cache_kobject); |
668 | 786 | ||
669 | struct _index_kobject { | 787 | struct _index_kobject { |
670 | struct kobject kobj; | 788 | struct kobject kobj; |
@@ -673,8 +791,8 @@ struct _index_kobject { | |||
673 | }; | 791 | }; |
674 | 792 | ||
675 | /* pointer to array of kobjects for cpuX/cache/indexY */ | 793 | /* pointer to array of kobjects for cpuX/cache/indexY */ |
676 | static DEFINE_PER_CPU(struct _index_kobject *, index_kobject); | 794 | static DEFINE_PER_CPU(struct _index_kobject *, ici_index_kobject); |
677 | #define INDEX_KOBJECT_PTR(x, y) (&((per_cpu(index_kobject, x))[y])) | 795 | #define INDEX_KOBJECT_PTR(x, y) (&((per_cpu(ici_index_kobject, x))[y])) |
678 | 796 | ||
679 | #define show_one_plus(file_name, object, val) \ | 797 | #define show_one_plus(file_name, object, val) \ |
680 | static ssize_t show_##file_name \ | 798 | static ssize_t show_##file_name \ |
@@ -740,82 +858,6 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) | |||
740 | #define to_object(k) container_of(k, struct _index_kobject, kobj) | 858 | #define to_object(k) container_of(k, struct _index_kobject, kobj) |
741 | #define to_attr(a) container_of(a, struct _cache_attr, attr) | 859 | #define to_attr(a) container_of(a, struct _cache_attr, attr) |
742 | 860 | ||
743 | static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, | ||
744 | unsigned int index) | ||
745 | { | ||
746 | int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); | ||
747 | int node = cpu_to_node(cpu); | ||
748 | struct pci_dev *dev = node_to_k8_nb_misc(node); | ||
749 | unsigned int reg = 0; | ||
750 | |||
751 | if (!this_leaf->can_disable) | ||
752 | return -EINVAL; | ||
753 | |||
754 | if (!dev) | ||
755 | return -EINVAL; | ||
756 | |||
757 | pci_read_config_dword(dev, 0x1BC + index * 4, ®); | ||
758 | return sprintf(buf, "%x\n", reg); | ||
759 | } | ||
760 | |||
761 | #define SHOW_CACHE_DISABLE(index) \ | ||
762 | 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 | SHOW_CACHE_DISABLE(0) | ||
768 | SHOW_CACHE_DISABLE(1) | ||
769 | |||
770 | static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, | ||
771 | 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 = cpu_to_node(cpu); | ||
775 | struct pci_dev *dev = node_to_k8_nb_misc(node); | ||
776 | unsigned long val = 0; | ||
777 | unsigned int scrubber = 0; | ||
778 | |||
779 | if (!this_leaf->can_disable) | ||
780 | return -EINVAL; | ||
781 | |||
782 | if (!capable(CAP_SYS_ADMIN)) | ||
783 | return -EPERM; | ||
784 | |||
785 | if (!dev) | ||
786 | return -EINVAL; | ||
787 | |||
788 | if (strict_strtoul(buf, 10, &val) < 0) | ||
789 | return -EINVAL; | ||
790 | |||
791 | val |= 0xc0000000; | ||
792 | |||
793 | pci_read_config_dword(dev, 0x58, &scrubber); | ||
794 | scrubber &= ~0x1f000000; | ||
795 | pci_write_config_dword(dev, 0x58, scrubber); | ||
796 | |||
797 | pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); | ||
798 | wbinvd(); | ||
799 | pci_write_config_dword(dev, 0x1BC + index * 4, val); | ||
800 | return count; | ||
801 | } | ||
802 | |||
803 | #define STORE_CACHE_DISABLE(index) \ | ||
804 | static ssize_t \ | ||
805 | store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ | ||
806 | const char *buf, size_t count) \ | ||
807 | { \ | ||
808 | return store_cache_disable(this_leaf, buf, count, index); \ | ||
809 | } | ||
810 | STORE_CACHE_DISABLE(0) | ||
811 | STORE_CACHE_DISABLE(1) | ||
812 | |||
813 | struct _cache_attr { | ||
814 | struct attribute attr; | ||
815 | ssize_t (*show)(struct _cpuid4_info *, char *); | ||
816 | ssize_t (*store)(struct _cpuid4_info *, const char *, size_t count); | ||
817 | }; | ||
818 | |||
819 | #define define_one_ro(_name) \ | 861 | #define define_one_ro(_name) \ |
820 | static struct _cache_attr _name = \ | 862 | static struct _cache_attr _name = \ |
821 | __ATTR(_name, 0444, show_##_name, NULL) | 863 | __ATTR(_name, 0444, show_##_name, NULL) |
@@ -830,23 +872,28 @@ define_one_ro(size); | |||
830 | define_one_ro(shared_cpu_map); | 872 | define_one_ro(shared_cpu_map); |
831 | define_one_ro(shared_cpu_list); | 873 | define_one_ro(shared_cpu_list); |
832 | 874 | ||
833 | static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, | 875 | #define DEFAULT_SYSFS_CACHE_ATTRS \ |
834 | show_cache_disable_0, store_cache_disable_0); | 876 | &type.attr, \ |
835 | static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, | 877 | &level.attr, \ |
836 | show_cache_disable_1, store_cache_disable_1); | 878 | &coherency_line_size.attr, \ |
879 | &physical_line_partition.attr, \ | ||
880 | &ways_of_associativity.attr, \ | ||
881 | &number_of_sets.attr, \ | ||
882 | &size.attr, \ | ||
883 | &shared_cpu_map.attr, \ | ||
884 | &shared_cpu_list.attr | ||
837 | 885 | ||
838 | static struct attribute *default_attrs[] = { | 886 | static struct attribute *default_attrs[] = { |
839 | &type.attr, | 887 | DEFAULT_SYSFS_CACHE_ATTRS, |
840 | &level.attr, | 888 | NULL |
841 | &coherency_line_size.attr, | 889 | }; |
842 | &physical_line_partition.attr, | 890 | |
843 | &ways_of_associativity.attr, | 891 | static struct attribute *default_l3_attrs[] = { |
844 | &number_of_sets.attr, | 892 | DEFAULT_SYSFS_CACHE_ATTRS, |
845 | &size.attr, | 893 | #ifdef CONFIG_CPU_SUP_AMD |
846 | &shared_cpu_map.attr, | ||
847 | &shared_cpu_list.attr, | ||
848 | &cache_disable_0.attr, | 894 | &cache_disable_0.attr, |
849 | &cache_disable_1.attr, | 895 | &cache_disable_1.attr, |
896 | #endif | ||
850 | NULL | 897 | NULL |
851 | }; | 898 | }; |
852 | 899 | ||
@@ -877,7 +924,7 @@ static ssize_t store(struct kobject *kobj, struct attribute *attr, | |||
877 | return ret; | 924 | return ret; |
878 | } | 925 | } |
879 | 926 | ||
880 | static struct sysfs_ops sysfs_ops = { | 927 | static const struct sysfs_ops sysfs_ops = { |
881 | .show = show, | 928 | .show = show, |
882 | .store = store, | 929 | .store = store, |
883 | }; | 930 | }; |
@@ -893,10 +940,10 @@ static struct kobj_type ktype_percpu_entry = { | |||
893 | 940 | ||
894 | static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu) | 941 | static void __cpuinit cpuid4_cache_sysfs_exit(unsigned int cpu) |
895 | { | 942 | { |
896 | kfree(per_cpu(cache_kobject, cpu)); | 943 | kfree(per_cpu(ici_cache_kobject, cpu)); |
897 | kfree(per_cpu(index_kobject, cpu)); | 944 | kfree(per_cpu(ici_index_kobject, cpu)); |
898 | per_cpu(cache_kobject, cpu) = NULL; | 945 | per_cpu(ici_cache_kobject, cpu) = NULL; |
899 | per_cpu(index_kobject, cpu) = NULL; | 946 | per_cpu(ici_index_kobject, cpu) = NULL; |
900 | free_cache_attributes(cpu); | 947 | free_cache_attributes(cpu); |
901 | } | 948 | } |
902 | 949 | ||
@@ -912,14 +959,14 @@ static int __cpuinit cpuid4_cache_sysfs_init(unsigned int cpu) | |||
912 | return err; | 959 | return err; |
913 | 960 | ||
914 | /* Allocate all required memory */ | 961 | /* Allocate all required memory */ |
915 | per_cpu(cache_kobject, cpu) = | 962 | per_cpu(ici_cache_kobject, cpu) = |
916 | kzalloc(sizeof(struct kobject), GFP_KERNEL); | 963 | kzalloc(sizeof(struct kobject), GFP_KERNEL); |
917 | if (unlikely(per_cpu(cache_kobject, cpu) == NULL)) | 964 | if (unlikely(per_cpu(ici_cache_kobject, cpu) == NULL)) |
918 | goto err_out; | 965 | goto err_out; |
919 | 966 | ||
920 | per_cpu(index_kobject, cpu) = kzalloc( | 967 | per_cpu(ici_index_kobject, cpu) = kzalloc( |
921 | sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL); | 968 | sizeof(struct _index_kobject) * num_cache_leaves, GFP_KERNEL); |
922 | if (unlikely(per_cpu(index_kobject, cpu) == NULL)) | 969 | if (unlikely(per_cpu(ici_index_kobject, cpu) == NULL)) |
923 | goto err_out; | 970 | goto err_out; |
924 | 971 | ||
925 | return 0; | 972 | return 0; |
@@ -937,13 +984,14 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) | |||
937 | unsigned int cpu = sys_dev->id; | 984 | unsigned int cpu = sys_dev->id; |
938 | unsigned long i, j; | 985 | unsigned long i, j; |
939 | struct _index_kobject *this_object; | 986 | struct _index_kobject *this_object; |
987 | struct _cpuid4_info *this_leaf; | ||
940 | int retval; | 988 | int retval; |
941 | 989 | ||
942 | retval = cpuid4_cache_sysfs_init(cpu); | 990 | retval = cpuid4_cache_sysfs_init(cpu); |
943 | if (unlikely(retval < 0)) | 991 | if (unlikely(retval < 0)) |
944 | return retval; | 992 | return retval; |
945 | 993 | ||
946 | retval = kobject_init_and_add(per_cpu(cache_kobject, cpu), | 994 | retval = kobject_init_and_add(per_cpu(ici_cache_kobject, cpu), |
947 | &ktype_percpu_entry, | 995 | &ktype_percpu_entry, |
948 | &sys_dev->kobj, "%s", "cache"); | 996 | &sys_dev->kobj, "%s", "cache"); |
949 | if (retval < 0) { | 997 | if (retval < 0) { |
@@ -955,14 +1003,22 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) | |||
955 | this_object = INDEX_KOBJECT_PTR(cpu, i); | 1003 | this_object = INDEX_KOBJECT_PTR(cpu, i); |
956 | this_object->cpu = cpu; | 1004 | this_object->cpu = cpu; |
957 | this_object->index = i; | 1005 | this_object->index = i; |
1006 | |||
1007 | this_leaf = CPUID4_INFO_IDX(cpu, i); | ||
1008 | |||
1009 | if (this_leaf->can_disable) | ||
1010 | ktype_cache.default_attrs = default_l3_attrs; | ||
1011 | else | ||
1012 | ktype_cache.default_attrs = default_attrs; | ||
1013 | |||
958 | retval = kobject_init_and_add(&(this_object->kobj), | 1014 | retval = kobject_init_and_add(&(this_object->kobj), |
959 | &ktype_cache, | 1015 | &ktype_cache, |
960 | per_cpu(cache_kobject, cpu), | 1016 | per_cpu(ici_cache_kobject, cpu), |
961 | "index%1lu", i); | 1017 | "index%1lu", i); |
962 | if (unlikely(retval)) { | 1018 | if (unlikely(retval)) { |
963 | for (j = 0; j < i; j++) | 1019 | for (j = 0; j < i; j++) |
964 | kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj)); | 1020 | kobject_put(&(INDEX_KOBJECT_PTR(cpu, j)->kobj)); |
965 | kobject_put(per_cpu(cache_kobject, cpu)); | 1021 | kobject_put(per_cpu(ici_cache_kobject, cpu)); |
966 | cpuid4_cache_sysfs_exit(cpu); | 1022 | cpuid4_cache_sysfs_exit(cpu); |
967 | return retval; | 1023 | return retval; |
968 | } | 1024 | } |
@@ -970,7 +1026,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev) | |||
970 | } | 1026 | } |
971 | cpumask_set_cpu(cpu, to_cpumask(cache_dev_map)); | 1027 | cpumask_set_cpu(cpu, to_cpumask(cache_dev_map)); |
972 | 1028 | ||
973 | kobject_uevent(per_cpu(cache_kobject, cpu), KOBJ_ADD); | 1029 | kobject_uevent(per_cpu(ici_cache_kobject, cpu), KOBJ_ADD); |
974 | return 0; | 1030 | return 0; |
975 | } | 1031 | } |
976 | 1032 | ||
@@ -979,7 +1035,7 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) | |||
979 | unsigned int cpu = sys_dev->id; | 1035 | unsigned int cpu = sys_dev->id; |
980 | unsigned long i; | 1036 | unsigned long i; |
981 | 1037 | ||
982 | if (per_cpu(cpuid4_info, cpu) == NULL) | 1038 | if (per_cpu(ici_cpuid4_info, cpu) == NULL) |
983 | return; | 1039 | return; |
984 | if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map))) | 1040 | if (!cpumask_test_cpu(cpu, to_cpumask(cache_dev_map))) |
985 | return; | 1041 | return; |
@@ -987,7 +1043,7 @@ static void __cpuinit cache_remove_dev(struct sys_device * sys_dev) | |||
987 | 1043 | ||
988 | for (i = 0; i < num_cache_leaves; i++) | 1044 | for (i = 0; i < num_cache_leaves; i++) |
989 | kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj)); | 1045 | kobject_put(&(INDEX_KOBJECT_PTR(cpu, i)->kobj)); |
990 | kobject_put(per_cpu(cache_kobject, cpu)); | 1046 | kobject_put(per_cpu(ici_cache_kobject, cpu)); |
991 | cpuid4_cache_sysfs_exit(cpu); | 1047 | cpuid4_cache_sysfs_exit(cpu); |
992 | } | 1048 | } |
993 | 1049 | ||