[PATCH 01/01] x86: L3 cache index disable for 2.6.26

Linux Kernel Mailing List, post #231,786
Author:
Date:
Subject:
 Mark Langsdorf
 2008-07-18 16:03:52
 [PATCH 01/01] x86: L3 cache index disable for 2.6.26
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 <[email protected]>

---

-Mark Langsdorf
Operating System Research Center
AMD


diff -r 3836aaac6e15 arch/x86/kernel/cpu/intel_cacheinfo.c
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c Tue Jul 15 14:55:36 2008 -0500
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c Thu Jul 17 16:18:40 2008 -0500
@@ -16,6 +16,7 @@

#include <asm/processor.h>
#include <asm/smp.h>
+#include <asm/k8.h>

#define LVL_1_INST 1
#define LVL_1_DATA 2
@@ -129,6 +130,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 */
};

@@ -250,6 +252,13 @@ 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;
@@ -257,9 +266,12 @@ 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
+ 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 ? */
@@ -636,6 +648,61 @@ static ssize_t show_type(struct _cpuid4_
}
}

+#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_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
+{
+ struct pci_dev *dev;
+ if (this_leaf->can_disable) {
+ int i;
+ ssize_t ret = 0;
+ int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+ dev = k8_northbridges[node];
+
+ for (i = 0; i < 2; i++) {
+ unsigned int reg;
+ pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
+ ret += sprintf(buf, "%sEntry: %d\n", buf, i);
+ ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n",
+ buf,
+ reg & 0x80000000 ? "Disabled" : "Allowed",
+ reg & 0x40000000 ? "Disabled" : "Allowed");
+ ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n", buf,
+ (reg & 0x30000) >> 16, reg & 0xfff);
+
+ }
+ return ret;
+ }
+ return sprintf(buf, "Feature not enabled\n");
+}
+
+static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf, size_t count)
+{
+ struct pci_dev *dev;
+ if (this_leaf->can_disable) {
+ /* write the MSR value */
+ unsigned int ret;
+ unsigned int index, val;
+ int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+ dev = k8_northbridges[node];
+
+ if (strlen(buf) > 15)
+ return -EINVAL;
+ ret = sscanf(buf, "%x %x", &index, &val);
+ if (ret != 2)
+ return -EINVAL;
+ if (index > 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 1;
+ }
+ return 0;
+}
+
struct _cache_attr {
struct attribute attr;
ssize_t (*show)(struct _cpuid4_info *, char *);
@@ -655,6 +722,8 @@ define_one_ro(size);
define_one_ro(size);
define_one_ro(shared_cpu_map);
define_one_ro(shared_cpu_list);
+
+static struct _cache_attr cache_disable = __ATTR(cache_disable, 0644, show_cache_disable, store_cache_disable);

static struct attribute * default_attrs[] = {
&type.attr,
@@ -666,11 +735,9 @@ static struct attribute * default_attrs[
&size.attr,
&shared_cpu_map.attr,
&shared_cpu_list.attr,
+ &cache_disable.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)
{
@@ -688,7 +755,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 [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/
Author:
Date:
Subject:
 Ingo Molnar
 2008-07-21 13:37:06
 Re: [PATCH 01/01] x86: L3 cache index disable for 2.6.26
* Mark Langsdorf <[email protected]> wrote:

> 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 <[email protected]>

applied to tip/x86/cpu, thanks Mark.

I've done some coding style fixes for the new functions you've
introduced, see that commit below.

Ingo

------------------->
commit 6cec0203a915739140c0a7fdf3498aa417123501
Author: Ingo Molnar <[email protected]>
Date: Mon Jul 21 13:34:21 2008 +0200

x86: L3 cache index disable for 2.6.26, cleanups

No change in functionality.

Signed-off-by: Ingo Molnar <[email protected]>
---
arch/x86/kernel/cpu/intel_cacheinfo.c | 115 +++++++++++++++++---------------
1 files changed, 61 insertions(+), 54 deletions(-)

diff --git a/arch/x86/kernel/cpu/intel_cacheinfo.c b/arch/x86/kernel/cpu/intel_cacheinfo.c
index 503c847..491892c 100644
--- a/arch/x86/kernel/cpu/intel_cacheinfo.c
+++ b/arch/x86/kernel/cpu/intel_cacheinfo.c
@@ -253,14 +253,16 @@ static void __cpuinit amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
(ebx->split.ways_of_associativity + 1) - 1;
}

-static void __cpuinit amd_check_l3_disable(int index, struct _cpuid4_info *this_leaf)
+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)
+static int
+__cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_leaf)
{
union _cpuid4_leaf_eax eax;
union _cpuid4_leaf_ebx ebx;
@@ -271,19 +273,20 @@ static int __cpuinit cpuid4_cache_lookup(int index, struct _cpuid4_info *this_le
amd_cpuid4(index, &eax, &ebx, &ecx);
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);
+ } else {
+ cpuid_count(4, index, &eax.full, &ebx.full, &ecx.full, &edx);
+ }
+
if (eax.split.type == CACHE_TYPE_NULL)
return -EIO; /* better error ? */

this_leaf->eax = eax;
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);
+ 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);
return 0;
}

@@ -649,59 +652,63 @@ static ssize_t show_type(struct _cpuid4_info *this_leaf, char *buf) {
}
}

-#define to_object(k) container_of(k, struct _index_kobject, kobj)
-#define to_attr(a) container_of(a, struct _cache_attr, attr)
+#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_cache_disable(struct _cpuid4_info *this_leaf, char *buf)
{
- struct pci_dev *dev;
- if (this_leaf->can_disable) {
- int i;
- ssize_t ret = 0;
- int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
- dev = k8_northbridges[node];
-
- for (i = 0; i < 2; i++) {
- unsigned int reg;
- pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
- ret += sprintf(buf, "%sEntry: %d\n", buf, i);
- ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n",
- buf,
- reg & 0x80000000 ? "Disabled" : "Allowed",
- reg & 0x40000000 ? "Disabled" : "Allowed");
- ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n", buf,
- (reg & 0x30000) >> 16, reg & 0xfff);
+ int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+ struct pci_dev *dev = k8_northbridges[node];
+ ssize_t ret = 0;
+ int i;

- }
- return ret;
+ if (!this_leaf->can_disable)
+ return sprintf(buf, "Feature not enabled\n");
+
+ for (i = 0; i < 2; i++) {
+ unsigned int reg;
+
+ pci_read_config_dword(dev, 0x1BC + i * 4, &reg);
+
+ ret += sprintf(buf, "%sEntry: %d\n", buf, i);
+ ret += sprintf(buf, "%sReads: %s\tNew Entries: %s\n",
+ buf,
+ reg & 0x80000000 ? "Disabled" : "Allowed",
+ reg & 0x40000000 ? "Disabled" : "Allowed");
+ ret += sprintf(buf, "%sSubCache: %x\tIndex: %x\n",
+ buf, (reg & 0x30000) >> 16, reg & 0xfff);
}
- return sprintf(buf, "Feature not enabled\n");
+ return ret;
}

-static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf, size_t count)
+static ssize_t
+store_cache_disable(struct _cpuid4_info *this_leaf, const char *buf,
+ size_t count)
{
- struct pci_dev *dev;
- if (this_leaf->can_disable) {
- /* write the MSR value */
- unsigned int ret;
- unsigned int index, val;
- int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
- dev = k8_northbridges[node];
-
- if (strlen(buf) > 15)
- return -EINVAL;
- ret = sscanf(buf, "%x %x", &index, &val);
- if (ret != 2)
- return -EINVAL;
- if (index > 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 1;
- }
- return 0;
+ int node = cpu_to_node(first_cpu(this_leaf->shared_cpu_map));
+ struct pci_dev *dev = k8_northbridges[node];
+ unsigned int ret, index, val;
+
+ if (!this_leaf->can_disable)
+ return 0;
+
+ /* write the MSR value */
+
+ if (strlen(buf) > 15)
+ return -EINVAL;
+
+ ret = sscanf(buf, "%x %x", &index, &val);
+ if (ret != 2)
+ return -EINVAL;
+ if (index > 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 1;
}

struct _cache_attr {
--
To unsubscribe from this list: send the line "unsubscribe linux-kernel" in
the body of a message to [email protected]
More majordomo info at http://vger.kernel.org/majordomo-info.html
Please read the FAQ at http://www.tux.org/lkml/