aboutsummaryrefslogtreecommitdiffstats
path: root/arch/x86/kernel
diff options
context:
space:
mode:
authorBorislav Petkov <borislav.petkov@amd.com>2010-01-22 10:01:05 -0500
committerH. Peter Anvin <hpa@zytor.com>2010-01-22 19:06:31 -0500
commitdcf39daf3d6d97f8741e82f0b9fb7554704ed2d1 (patch)
tree5659b2ca396e48cd955cd9d2ee3eacbddb904d9f /arch/x86/kernel
parent48a719c238bcbb72d6da79de9c5b3b93ab472107 (diff)
x86, cacheinfo: Fix disabling of L3 cache indices
* Correct the masks used for writing the cache index disable indices. * Do not turn off L3 scrubber - it is not necessary. * Make sure wbinvd is executed on the same node where the L3 is. * Check for out-of-bounds values written to the registers. * Make show_cache_disable hex values unambiguous * Check for Erratum #388 Signed-off-by: Borislav Petkov <borislav.petkov@amd.com> LKML-Reference: <1264172467-25155-4-git-send-email-bp@amd64.org> Signed-off-by: H. Peter Anvin <hpa@zytor.com>
Diffstat (limited to 'arch/x86/kernel')
-rw-r--r--arch/x86/kernel/cpu/intel_cacheinfo.c34
1 files changed, 21 insertions, 13 deletions
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index fc6c8ef92dcc..08c91abc4d32 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
@@ -299,8 +300,10 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
299 if (boot_cpu_data.x86 == 0x11) 300 if (boot_cpu_data.x86 == 0x11)
300 return; 301 return;
301 302
302 /* see erratum #382 */ 303 /* see errata #382 and #388 */
303 if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) 304 if ((boot_cpu_data.x86 == 0x10) &&
305 ((boot_cpu_data.x86_model < 0x9) ||
306 (boot_cpu_data.x86_mask < 0x1)))
304 return; 307 return;
305 308
306 this_leaf->can_disable = 1; 309 this_leaf->can_disable = 1;
@@ -726,12 +729,12 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
726 return -EINVAL; 729 return -EINVAL;
727 730
728 pci_read_config_dword(dev, 0x1BC + index * 4, &reg); 731 pci_read_config_dword(dev, 0x1BC + index * 4, &reg);
729 return sprintf(buf, "%x\n", reg); 732 return sprintf(buf, "0x%08x\n", reg);
730} 733}
731 734
732#define SHOW_CACHE_DISABLE(index) \ 735#define SHOW_CACHE_DISABLE(index) \
733static ssize_t \ 736static ssize_t \
734show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ 737show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \
735{ \ 738{ \
736 return show_cache_disable(this_leaf, buf, index); \ 739 return show_cache_disable(this_leaf, buf, index); \
737} 740}
@@ -745,7 +748,9 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
745 int node = cpu_to_node(cpu); 748 int node = cpu_to_node(cpu);
746 struct pci_dev *dev = node_to_k8_nb_misc(node); 749 struct pci_dev *dev = node_to_k8_nb_misc(node);
747 unsigned long val = 0; 750 unsigned long val = 0;
748 unsigned int scrubber = 0; 751
752#define SUBCACHE_MASK (3UL << 20)
753#define SUBCACHE_INDEX 0xfff
749 754
750 if (!this_leaf->can_disable) 755 if (!this_leaf->can_disable)
751 return -EINVAL; 756 return -EINVAL;
@@ -759,21 +764,24 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
759 if (strict_strtoul(buf, 10, &val) < 0) 764 if (strict_strtoul(buf, 10, &val) < 0)
760 return -EINVAL; 765 return -EINVAL;
761 766
762 val |= 0xc0000000; 767 /* do not allow writes outside of allowed bits */
763 768 if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX))
764 pci_read_config_dword(dev, 0x58, &scrubber); 769 return -EINVAL;
765 scrubber &= ~0x1f000000;
766 pci_write_config_dword(dev, 0x58, scrubber);
767 770
768 pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); 771 val |= BIT(30);
769 wbinvd();
770 pci_write_config_dword(dev, 0x1BC + index * 4, val); 772 pci_write_config_dword(dev, 0x1BC + index * 4, val);
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));
771 return count; 779 return count;
772} 780}
773 781
774#define STORE_CACHE_DISABLE(index) \ 782#define STORE_CACHE_DISABLE(index) \
775static ssize_t \ 783static ssize_t \
776store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ 784store_cache_disable_##index(struct _cpuid4_info *this_leaf, \
777 const char *buf, size_t count) \ 785 const char *buf, size_t count) \
778{ \ 786{ \
779 return store_cache_disable(this_leaf, buf, count, index); \ 787 return store_cache_disable(this_leaf, buf, count, index); \