diff options
Diffstat (limited to 'arch/x86/kernel/cpu/intel_cacheinfo.c')
| -rw-r--r-- | arch/x86/kernel/cpu/intel_cacheinfo.c | 153 |
1 files changed, 72 insertions, 81 deletions
diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c index 483eda96e102..789efe217e1a 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c | |||
| @@ -17,6 +17,7 @@ | |||
| 17 | 17 | ||
| 18 | #include <asm/processor.h> | 18 | #include <asm/processor.h> |
| 19 | #include <asm/smp.h> | 19 | #include <asm/smp.h> |
| 20 | #include <asm/k8.h> | ||
| 20 | 21 | ||
| 21 | #define LVL_1_INST 1 | 22 | #define LVL_1_INST 1 |
| 22 | #define LVL_1_DATA 2 | 23 | #define LVL_1_DATA 2 |
| @@ -159,14 +160,6 @@ struct _cpuid4_info_regs { | |||
| 159 | unsigned long can_disable; | 160 | unsigned long can_disable; |
| 160 | }; | 161 | }; |
| 161 | 162 | ||
| 162 | #if defined(CONFIG_PCI) && defined(CONFIG_SYSFS) | ||
| 163 | static struct pci_device_id k8_nb_id[] = { | ||
| 164 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, | ||
| 165 | { PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) }, | ||
| 166 | {} | ||
| 167 | }; | ||
| 168 | #endif | ||
| 169 | |||
| 170 | unsigned short num_cache_leaves; | 163 | unsigned short num_cache_leaves; |
| 171 | 164 | ||
| 172 | /* AMD doesn't have CPUID4. Emulate it here to report the same | 165 | /* AMD doesn't have CPUID4. Emulate it here to report the same |
| @@ -207,10 +200,17 @@ union l3_cache { | |||
| 207 | }; | 200 | }; |
| 208 | 201 | ||
| 209 | static const unsigned short __cpuinitconst assocs[] = { | 202 | static const unsigned short __cpuinitconst assocs[] = { |
| 210 | [1] = 1, [2] = 2, [4] = 4, [6] = 8, | 203 | [1] = 1, |
| 211 | [8] = 16, [0xa] = 32, [0xb] = 48, | 204 | [2] = 2, |
| 205 | [4] = 4, | ||
| 206 | [6] = 8, | ||
| 207 | [8] = 16, | ||
| 208 | [0xa] = 32, | ||
| 209 | [0xb] = 48, | ||
| 212 | [0xc] = 64, | 210 | [0xc] = 64, |
| 213 | [0xf] = 0xffff // ?? | 211 | [0xd] = 96, |
| 212 | [0xe] = 128, | ||
| 213 | [0xf] = 0xffff /* fully associative - no way to show this currently */ | ||
| 214 | }; | 214 | }; |
| 215 | 215 | ||
| 216 | static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 }; | 216 | static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 }; |
| @@ -271,7 +271,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax, | |||
| 271 | eax->split.type = types[leaf]; | 271 | eax->split.type = types[leaf]; |
| 272 | eax->split.level = levels[leaf]; | 272 | eax->split.level = levels[leaf]; |
| 273 | if (leaf == 3) | 273 | if (leaf == 3) |
| 274 | eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1; | 274 | eax->split.num_threads_sharing = |
| 275 | current_cpu_data.x86_max_cores - 1; | ||
| 275 | else | 276 | else |
| 276 | eax->split.num_threads_sharing = 0; | 277 | eax->split.num_threads_sharing = 0; |
| 277 | eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1; | 278 | eax->split.num_cores_on_die = current_cpu_data.x86_max_cores - 1; |
| @@ -291,6 +292,14 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf) | |||
| 291 | { | 292 | { |
| 292 | if (index < 3) | 293 | if (index < 3) |
| 293 | return; | 294 | return; |
| 295 | |||
| 296 | if (boot_cpu_data.x86 == 0x11) | ||
| 297 | return; | ||
| 298 | |||
| 299 | /* see erratum #382 */ | ||
| 300 | if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) | ||
| 301 | return; | ||
| 302 | |||
| 294 | this_leaf->can_disable = 1; | 303 | this_leaf->can_disable = 1; |
| 295 | } | 304 | } |
| 296 | 305 | ||
| @@ -696,97 +705,75 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) | |||
| 696 | #define to_object(k) container_of(k, struct _index_kobject, kobj) | 705 | #define to_object(k) container_of(k, struct _index_kobject, kobj) |
| 697 | #define to_attr(a) container_of(a, struct _cache_attr, attr) | 706 | #define to_attr(a) container_of(a, struct _cache_attr, attr) |
| 698 | 707 | ||
| 699 | #ifdef CONFIG_PCI | 708 | static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, |
| 700 | static struct pci_dev *get_k8_northbridge(int node) | 709 | unsigned int index) |
| 701 | { | ||
| 702 | struct pci_dev *dev = NULL; | ||
| 703 | int i; | ||
| 704 | |||
| 705 | for (i = 0; i <= node; i++) { | ||
| 706 | do { | ||
| 707 | dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); | ||
| 708 | if (!dev) | ||
| 709 | break; | ||
| 710 | } while (!pci_match_id(&k8_nb_id[0], dev)); | ||
| 711 | if (!dev) | ||
| 712 | break; | ||
| 713 | } | ||
| 714 | return dev; | ||
| 715 | } | ||
| 716 | #else | ||
| 717 | static struct pci_dev *get_k8_northbridge(int node) | ||
| 718 | { | ||
| 719 | return NULL; | ||
| 720 | } | ||
| 721 | #endif | ||
| 722 | |||
| 723 | static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf) | ||
| 724 | { | 710 | { |
| 725 | const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); | 711 | int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); |
| 726 | int node = cpu_to_node(cpumask_first(mask)); | 712 | int node = cpu_to_node(cpu); |
| 727 | struct pci_dev *dev = NULL; | 713 | struct pci_dev *dev = node_to_k8_nb_misc(node); |
| 728 | ssize_t ret = 0; | 714 | unsigned int reg = 0; |
| 729 | int i; | ||
| 730 | 715 | ||
| 731 | if (!this_leaf->can_disable) | 716 | if (!this_leaf->can_disable) |
| 732 | return sprintf(buf, "Feature not enabled\n"); | ||
| 733 | |||
| 734 | dev = get_k8_northbridge(node); | ||
| 735 | if (!dev) { | ||
| 736 | printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n"); | ||
| 737 | return -EINVAL; | 717 | return -EINVAL; |
| 738 | } | ||
| 739 | 718 | ||
| 740 | for (i = 0; i < 2; i++) { | 719 | if (!dev) |
| 741 | unsigned int reg; | 720 | return -EINVAL; |
| 742 | 721 | ||
| 743 | pci_read_config_dword(dev, 0x1BC + i * 4, ®); | 722 | pci_read_config_dword(dev, 0x1BC + index * 4, ®); |
| 723 | return sprintf(buf, "%x\n", reg); | ||
| 724 | } | ||
| 744 | 725 | ||
| 745 | ret += sprintf(buf, "%sEntry: %d\n", buf, i); | 726 | #define SHOW_CACHE_DISABLE(index) \ |
| 746 | ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n", | 727 | static ssize_t \ |
| 747 | buf, | 728 | show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ |
| 748 | reg & 0x80000000 ? "Disabled" : "Allowed", | 729 | { \ |
| 749 | reg & 0x40000000 ? "Disabled" : "Allowed"); | 730 | return show_cache_disable(this_leaf, buf, index); \ |
| 750 | ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n", | ||
| 751 | buf, (reg & 0x30000) >> 16, reg & 0xfff); | ||
| 752 | } | ||
| 753 | return ret; | ||
| 754 | } | 731 | } |
| 732 | SHOW_CACHE_DISABLE(0) | ||
| 733 | SHOW_CACHE_DISABLE(1) | ||
| 755 | 734 | ||
| 756 | static ssize_t | 735 | static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, |
| 757 | store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf, | 736 | const char *buf, size_t count, unsigned int index) |
| 758 | size_t count) | ||
| 759 | { | 737 | { |
| 760 | const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); | 738 | int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); |
| 761 | int node = cpu_to_node(cpumask_first(mask)); | 739 | int node = cpu_to_node(cpu); |
| 762 | struct pci_dev *dev = NULL; | 740 | struct pci_dev *dev = node_to_k8_nb_misc(node); |
| 763 | unsigned int ret, index, val; | 741 | unsigned long val = 0; |
| 742 | unsigned int scrubber = 0; | ||
| 764 | 743 | ||
| 765 | if (!this_leaf->can_disable) | 744 | if (!this_leaf->can_disable) |
| 766 | return 0; | ||
| 767 | |||
| 768 | if (strlen(buf) > 15) | ||
| 769 | return -EINVAL; | 745 | return -EINVAL; |
| 770 | 746 | ||
| 771 | ret = sscanf(buf, "%x %x", &index, &val); | 747 | if (!capable(CAP_SYS_ADMIN)) |
| 772 | if (ret != 2) | 748 | return -EPERM; |
| 749 | |||
| 750 | if (!dev) | ||
| 773 | return -EINVAL; | 751 | return -EINVAL; |
| 774 | if (index > 1) | 752 | |
| 753 | if (strict_strtoul(buf, 10, &val) < 0) | ||
| 775 | return -EINVAL; | 754 | return -EINVAL; |
| 776 | 755 | ||
| 777 | val |= 0xc0000000; | 756 | val |= 0xc0000000; |
| 778 | dev = get_k8_northbridge(node); | 757 | |
| 779 | if (!dev) { | 758 | pci_read_config_dword(dev, 0x58, &scrubber); |
| 780 | printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n"); | 759 | scrubber &= ~0x1f000000; |
| 781 | return -EINVAL; | 760 | pci_write_config_dword(dev, 0x58, scrubber); |
| 782 | } | ||
| 783 | 761 | ||
| 784 | pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); | 762 | pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); |
| 785 | wbinvd(); | 763 | wbinvd(); |
| 786 | pci_write_config_dword(dev, 0x1BC + index * 4, val); | 764 | pci_write_config_dword(dev, 0x1BC + index * 4, val); |
| 765 | return count; | ||
| 766 | } | ||
| 787 | 767 | ||
| 788 | return 1; | 768 | #define STORE_CACHE_DISABLE(index) \ |
| 769 | static ssize_t \ | ||
| 770 | store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ | ||
| 771 | const char *buf, size_t count) \ | ||
| 772 | { \ | ||
| 773 | return store_cache_disable(this_leaf, buf, count, index); \ | ||
| 789 | } | 774 | } |
| 775 | STORE_CACHE_DISABLE(0) | ||
| 776 | STORE_CACHE_DISABLE(1) | ||
| 790 | 777 | ||
| 791 | struct _cache_attr { | 778 | struct _cache_attr { |
| 792 | struct attribute attr; | 779 | struct attribute attr; |
| @@ -808,7 +795,10 @@ define_one_ro(size); | |||
| 808 | define_one_ro(shared_cpu_map); | 795 | define_one_ro(shared_cpu_map); |
| 809 | define_one_ro(shared_cpu_list); | 796 | define_one_ro(shared_cpu_list); |
| 810 | 797 | ||
| 811 | static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable); | 798 | static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, |
| 799 | show_cache_disable_0, store_cache_disable_0); | ||
| 800 | static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, | ||
| 801 | show_cache_disable_1, store_cache_disable_1); | ||
| 812 | 802 | ||
| 813 | static struct attribute * default_attrs[] = { | 803 | static struct attribute * default_attrs[] = { |
| 814 | &type.attr, | 804 | &type.attr, |
| @@ -820,7 +810,8 @@ static struct attribute * default_attrs[] = { | |||
| 820 | &size.attr, | 810 | &size.attr, |
| 821 | &shared_cpu_map.attr, | 811 | &shared_cpu_map.attr, |
| 822 | &shared_cpu_list.attr, | 812 | &shared_cpu_list.attr, |
| 823 | &cache_disable.attr, | 813 | &cache_disable_0.attr, |
| 814 | &cache_disable_1.attr, | ||
| 824 | NULL | 815 | NULL |
| 825 | }; | 816 | }; |
| 826 | 817 | ||
