diff options
author | Borislav Petkov <borislav.petkov@amd.com> | 2010-01-22 10:01:05 -0500 |
---|---|---|
committer | H. Peter Anvin <hpa@zytor.com> | 2010-01-22 19:06:31 -0500 |
commit | dcf39daf3d6d97f8741e82f0b9fb7554704ed2d1 (patch) | |
tree | 5659b2ca396e48cd955cd9d2ee3eacbddb904d9f /arch/x86/kernel | |
parent | 48a719c238bcbb72d6da79de9c5b3b93ab472107 (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.c | 34 |
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, ®); | 731 | pci_read_config_dword(dev, 0x1BC + index * 4, ®); |
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) \ |
733 | static ssize_t \ | 736 | static ssize_t \ |
734 | show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ | 737 | show_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) \ |
775 | static ssize_t \ | 783 | static ssize_t \ |
776 | store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ | 784 | store_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); \ |