Return-Path: Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1759196AbYHNNii (ORCPT ); Thu, 14 Aug 2008 09:38:38 -0400 Received: (majordomo@vger.kernel.org) by vger.kernel.org id S1750980AbYHNNib (ORCPT ); Thu, 14 Aug 2008 09:38:31 -0400 Received: from outbound-sin.frontbridge.com ([207.46.51.80]:46141 "EHLO SG2EHSOBE002.bigfish.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1750840AbYHNNia convert rfc822-to-8bit (ORCPT ); Thu, 14 Aug 2008 09:38:30 -0400 X-BigFish: VPS-61(z21eWz13e6IL936eQ936fQzz10d3izz5eeeTz32i6bh43j62h) X-Spam-TCS-SCL: 1:0 X-WSS-ID: 0K5LF7N-01-RR7-01 From: Mark Langsdorf To: Greg KH Subject: Re: [PATCH 01/01][retry 3] x86: L3 cache index disable for 2.6.26 Date: Thu, 14 Aug 2008 08:43:43 -0500 User-Agent: KMail/1.9.9 CC: Pavel Machek , joachim.deguara@amd.com, gregkh@ucw.cz, tglx@linutronix.de, mingo@redhat.com, hpa@zytor.com, linux-kernel@vger.kernel.org References: <200807181603.52332.mark.langsdorf@amd.com> <200808131502.42611.mark.langsdorf@amd.com> <20080813234503.GA32154@kroah.com> In-Reply-To: <20080813234503.GA32154@kroah.com> MIME-Version: 1.0 Content-Type: text/plain; charset="iso-8859-1" Content-Transfer-Encoding: 8BIT Content-Disposition: inline Message-ID: <200808140843.44090.mark.langsdorf@amd.com> X-OriginalArrivalTime: 14 Aug 2008 13:38:17.0052 (UTC) FILETIME=[01F1D9C0:01C8FE13] Sender: linux-kernel-owner@vger.kernel.org List-ID: X-Mailing-List: linux-kernel@vger.kernel.org Content-Length: 7984 Lines: 242 New versions of AMD processors have support to disable parts of their L3 caches if too many MCEs are generated by the L3 cache. ? This patch provides a /sysfs interface under the cache hierarchy to display which caches indices are disabled (if any) and to monitoring applications to disable a cache index. This patch does not set an automatic policy to disable the L3 cache. ?Policy decisions would need to be made by a RAS handler. ?This patch merely makes it easier to see what indices are currently disabled. Signed-off-by: Mark Langsdorf diff -r e683983d4dd0 Documentation/ABI/testing/sysfs-devices-cache_disable --- /dev/null Thu Jan 01 00:00:00 1970 +0000 +++ b/Documentation/ABI/testing/sysfs-devices-cache_disable Thu Aug 14 02:54:30 2008 -0500 @@ -0,0 +1,18 @@ +What: /sys/devices/system/cpu/cpu*/cache/index*/cache_disable_X +Date: Augsust 2008 +KernelVersion: 2.6.27 +Contact: mark.langsdorf@amd.com +Description: These files exist in every cpu's cache index directories. + There are currently 2 cache_disable_# files in each + directory. Reading from these files on a supported + processor will return that cache disable index value + for that processor and node. Writing to one of these + files will cause the specificed cache index to be disable. + + Currently, only AMD Family 10h Processors support cache index + disable, and only for their L3 caches. See the BIOS and + Kernel Developer's Guide at + http://www.amd.com/us-en/assets/content_type/white_papers_and_tech_docs/31116.PDF + for formatting information and other details on the + cache index disable. +Users: joachim.deguara@amd.com diff -r e683983d4dd0 arch/x86/kernel/cpu/intel_cacheinfo.c --- a/arch/x86/kernel/cpu/intel_cacheinfo.c Tue Aug 12 08:46:38 2008 -0500 +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c Thu Aug 14 02:54:00 2008 -0500 @@ -16,6 +16,9 @@ #include #include + +#include +#include #define LVL_1_INST 1 #define LVL_1_DATA 2 @@ -130,6 +133,7 @@ struct _cpuid4_info { union _cpuid4_leaf_ebx ebx; union _cpuid4_leaf_ecx ecx; unsigned long size; + unsigned long can_disable; cpumask_t shared_cpu_map; /* future?: only cpus/node is needed */ }; @@ -251,6 +255,14 @@ static void __cpuinit amd_cpuid4(int lea (ebx->split.ways_of_associativity + 1) - 1; } +static void __cpuinit +amd_check_l3_disable(int index, struct _cpuid4_info *this_leaf) +{ + if (index < 3) + return; + this_leaf->can_disable = 1; +} + static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf) { union _cpuid4_leaf_eax eax; @@ -258,10 +270,13 @@ static int __cpuinit cpuid4_cache_lookup union _cpuid4_leaf_ecx ecx; unsigned edx; - if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) + if (boot_cpu_data.x86_vendor == X86_VENDOR_AMD) { amd_cpuid4(index, &eax, &ebx, &ecx); - else - cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx); + if (boot_cpu_data.x86 >= 0x10) + amd_check_l3_disable(index, this_leaf); + } else { + cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx); + } if (eax.split.type == CACHE_TYPE_NULL) return -EIO; /* better error ? */ @@ -269,9 +284,9 @@ static int __cpuinit cpuid4_cache_lookup this_leaf->ebx = ebx; this_leaf->ecx = ecx; this_leaf->size = (ecx.split.number_of_sets + 1) * - (ebx.split.coherency_line_size + 1) * - (ebx.split.physical_line_partition + 1) * - (ebx.split.ways_of_associativity + 1); + (ebx.split.coherency_line_size + 1) * + (ebx.split.physical_line_partition + 1) * + (ebx.split.ways_of_associativity + 1); return 0; } @@ -574,6 +589,9 @@ static DEFINE_PER_CPU(struct _index_kobj static DEFINE_PER_CPU(struct _index_kobject *, index_kobject); #define INDEX_KOBJECT_PTR(x, y) (&((per_cpu(index_kobject, x))[y])) +#define to_object(k) container_of(k, struct _index_kobject, kobj) +#define to_attr(a) container_of(a, struct _cache_attr, attr) + #define show_one_plus(file_name, object, val) \ static ssize_t show_##file_name \ (struct _cpuid4_info *this_leaf, char *buf) \ @@ -619,6 +637,78 @@ static inline ssize_t show_shared_cpu_li { return show_shared_cpu_map_func(leaf, 1, buf); } + +#if defined(CONFIG_PCI) && defined(CONFIG_K8_NB) +static struct pci_dev *get_k8_northbridge(int node) +{ + return k8_northbridges[node]; +} +#else +static struct pci_dev *get_k8_northbridge(int node) +{ + return NULL; +} +#endif + +static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, + unsigned int index) +{ + int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map)); + struct pci_dev *dev = get_k8_northbridge(node); + unsigned int reg = 0; + + if (!this_leaf->can_disable) + return -EINVAL; + + pci_read_config_dword(dev, 0x1BC + index * 4, ®); + return sprintf(buf, "%x\n", reg); +} + +#define SHOW_CACHE_DISABLE(index) \ +static ssize_t \ +show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf) \ +{ \ + return show_cache_disable(this_leaf, buf, index); \ +} + +static ssize_t +store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf, + size_t count, unsigned int index) +{ + int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map)); + struct pci_dev *dev = get_k8_northbridge(node); + ssize_t ret = 0; + unsigned int val; + + if (!this_leaf->can_disable) + return -EINVAL; + + if (strlen(buf) > 10) + return -EINVAL; + + ret = sscanf(buf, "%x", &val); + if (ret != 1) + return -EINVAL; + + val |= 0xc0000000; + pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000); + wbinvd(); + pci_write_config_dword(dev, 0x1BC + index * 4, val); + return ret ? ret : count; +} + +#define STORE_CACHE_DISABLE(index) \ +static ssize_t \ +store_cache_disable_##index(struct _cpuid4_info *this_leaf, \ + const char *buf, size_t count) \ +{ \ + return store_cache_disable(this_leaf, buf, count, index); \ +} + +SHOW_CACHE_DISABLE(0) +STORE_CACHE_DISABLE(0) +SHOW_CACHE_DISABLE(1) +STORE_CACHE_DISABLE(1) static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) { switch(this_leaf->eax.split.type) { @@ -657,6 +747,10 @@ define_one_ro(shared_cpu_map); define_one_ro(shared_cpu_map); define_one_ro(shared_cpu_list); +static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644, show_cache_disable_0, store_cache_disable_0); +static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644, show_cache_disable_1, store_cache_disable_1); + + static struct attribute * default_attrs[] = { &type.attr, &level.attr, @@ -667,11 +761,10 @@ static struct attribute * default_attrs[ &size.attr, &shared_cpu_map.attr, &shared_cpu_list.attr, + &cache_disable_0.attr, + &cache_disable_1.attr, NULL }; - -#define to_object(k) container_of(k, struct _index_kobject, kobj) -#define to_attr(a) container_of(a, struct _cache_attr, attr) static ssize_t show(struct kobject * kobj, struct attribute * attr, char * buf) { @@ -689,7 +782,15 @@ static ssize_t store(struct kobject * ko static ssize_t store(struct kobject * kobj, struct attribute * attr, const char * buf, size_t count) { - return 0; + struct _cache_attr *fattr = to_attr(attr); + struct _index_kobject *this_leaf = to_object(kobj); + ssize_t ret; + + ret = fattr->store ? + fattr->store(CPUID4_INFO_IDX(this_leaf->cpu, this_leaf->index), + buf, count) : + 0; + return ret; } static struct sysfs_ops sysfs_ops = { -- To unsubscribe from this list: send the line "unsubscribe linux-kernel" in the body of a message to majordomo@vger.kernel.org More majordomo info at http://vger.kernel.org/majordomo-info.html Please read the FAQ at http://www.tux.org/lkml/