Skip to contentSkip to conversation

x86, cacheinfo, amd: L3 Cache Index Disable fixes

PATCH In review Borislav Petkov 2 participants 12 messages Jan 21, 2010

Subsystems (3)
lore
Share & tools
lore
#0 lore raw

cover x86, cacheinfo, amd: L3 Cache Index Disable fixes

From: Borislav Petkov <[email protected]>

Changelog:

-v2: Split smp functionality into a different module

===
these are a bunch of fixes which correct the disabling of L3 cache indexes. This is needed, for example, in the case when excessive correctable L3 error rates are observed. In a later step, this functionality will be connected to the mcheck mechanism and used to evaluate occurring L3 tag and data array errors and then disable the respective failing L3 cache regions in order to defer system failure before a sysop can intervene.

Those patches are also good -stable candidates.

Please apply,
thanks.

#1 lore raw

PATCH 1/7 x86, smp: Convert msr-smp.c to an smp library

From: Borislav Petkov <[email protected]>

Put all smp-related helpers into lib/smp.c to use for the rest of the kernel.

---
 arch/x86/lib/Makefile  |    2 +-
 arch/x86/lib/msr-smp.c |  204 ------------------------------------------------
 arch/x86/lib/smp.c     |  204 ++++++++++++++++++++++++++++++++++++++++++++++++
 3 files changed, 205 insertions(+), 205 deletions(-)
 delete mode 100644 arch/x86/lib/msr-smp.c
 create mode 100644 arch/x86/lib/smp.c
arch/x86/lib/Makefile +1 -1
index cffd754..48a5ced 100644
@@ -14,7 +14,7 @@ $(obj)/inat.o: $(obj)/inat-tables.c
 
 clean-files := inat-tables.c
 
-obj-$(CONFIG_SMP) += msr-smp.o
+obj-$(CONFIG_SMP) += smp.o
 
 lib-y := delay.o
 lib-y += thunk_$(BITS).o
arch/x86/lib/msr-smp.c deleted +0 -204

204 lines not on this page · raw message

arch/x86/lib/smp.c new file +204 -0

204 lines not on this page · raw message

Signature · 1 line
1.6.6
#2 lore raw

Re: [PATCH 1/7] x86, smp: Convert msr-smp.c to an smp library

Quoted 5 lines · Borislav Petkov

From: Borislav Petkov <[email protected]>

Put all smp-related helpers into lib/smp.c to use for the rest of the kernel.

NAK. It's better to have more and smaller source files rather than fewer and larger. Create a new file for the wbinvd helpers.

-hpa

#3 lore raw

PATCH 2/7 x86, smp: Adjust native_wbinvd for smp_call_function-helpers

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

Add a wbinvd_on_cpu() helper and fold the void * arg in the wbinvd macro definition so that native_wbinvd can be used in the smp_call_function_* helpers as a pointed-to function.

---
 arch/x86/include/asm/paravirt.h       |    3 ++-
 arch/x86/include/asm/paravirt_types.h |    2 +-
 arch/x86/include/asm/smp.h            |    3 +++
 arch/x86/include/asm/system.h         |   10 ++++++++--
 arch/x86/lib/smp.c                    |    7 +++++++
 5 files changed, 21 insertions(+), 4 deletions(-)
arch/x86/include/asm/paravirt.h +2 -1
index dd59a85..ee034a6 100644
@@ -117,7 +117,8 @@ static inline void halt(void)
 
 static inline void wbinvd(void)
 {
-	PVOP_VCALL0(pv_cpu_ops.wbinvd);
+	void *uninitialized_var(dummy_ptr);
+	PVOP_VCALL1(pv_cpu_ops.wbinvd, dummy_ptr);
 }
 
 #define get_kernel_rpl()  (pv_info.kernel_rpl)
arch/x86/include/asm/paravirt_types.h +1 -1
index b1e70d5..79730b8 100644
@@ -136,7 +136,7 @@ struct pv_cpu_ops {
 
 	void (*set_iopl_mask)(unsigned mask);
 
-	void (*wbinvd)(void);
+	void (*wbinvd)(void *);
 	void (*io_delay)(void);
 
 	/* cpuid emulation, mostly so that caps bits can be disabled */
arch/x86/include/asm/smp.h +3 -0
index 1e79678..090146e 100644
@@ -138,6 +138,7 @@ void play_dead_common(void);
 
 void native_send_call_func_ipi(const struct cpumask *mask);
 void native_send_call_func_single_ipi(int cpu);
+void wbinvd_on_cpu(int cpu);
 
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
@@ -147,6 +148,8 @@ static inline int num_booting_cpus(void)
 {
 	return cpumask_weight(cpu_callout_mask);
 }
+#else /* !CONFIG_SMP */
+#define wbinvd_on_cpu(cpu)	wbinvd()
 #endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus __cpuinitdata;
arch/x86/include/asm/system.h +8 -2
index ecb544e..8c531ab 100644
@@ -297,7 +297,7 @@ static inline void native_write_cr8(unsigned long val)
 }
 #endif
 
-static inline void native_wbinvd(void)
+static inline void native_wbinvd(void *dummy)
 {
 	asm volatile("wbinvd": : :"memory");
 }
@@ -314,7 +314,13 @@ static inline void native_wbinvd(void)
 #define read_cr4()	(native_read_cr4())
 #define read_cr4_safe()	(native_read_cr4_safe())
 #define write_cr4(x)	(native_write_cr4(x))
-#define wbinvd()	(native_wbinvd())
+
+#define wbinvd()					\
+	({						\
+		void *uninitialized_var(dumb_ptr);	\
+		native_wbinvd(dumb_ptr);		\
+	})
+
 #ifdef CONFIG_X86_64
 #define read_cr8()	(native_read_cr8())
 #define write_cr8(x)	(native_write_cr8(x))
arch/x86/lib/smp.c +7 -0
index a6b1b86..408c3b7 100644
@@ -2,6 +2,7 @@
 #include <linux/preempt.h>
 #include <linux/smp.h>
 #include <asm/msr.h>
+#include <asm/system.h>
 
 static void __rdmsr_on_cpu(void *info)
 {
@@ -202,3 +203,9 @@ int wrmsr_safe_regs_on_cpu(unsigned int cpu, u32 *regs)
 	return err ? err : rv.err;
 }
 EXPORT_SYMBOL(wrmsr_safe_regs_on_cpu);
+
+void wbinvd_on_cpu(int cpu)
+{
+	smp_call_function_single(cpu, native_wbinvd, NULL, 1);
+}
+EXPORT_SYMBOL(wbinvd_on_cpu);
Signature · 1 line
1.6.6
#4 lore raw

Re: [PATCH 2/7] x86, smp: Adjust native_wbinvd for smp_call_function-helpers

Quoted 7 lines · Borislav Petkov

From: Borislav Petkov <[email protected]>

Add a wbinvd_on_cpu() helper and fold the void * arg in the wbinvd macro definition so that native_wbinvd can be used in the smp_call_function_* helpers as a pointed-to function.

This patch is a lot of extra uglification just to avoid a simple jump stub -- and even then only with PV enabled -- for an operation which is then going to perform an IPI and WBINVD. That doesn't exactly seem like the right tradeoff.

As such, I'm going to request that you just put a simple stub function in lib/smp.c rather than this whole patchset (well, the smp.h bit obviously needs to stay.)

-hpa

#5 lore raw

Re: [PATCH 2/7] x86, smp: Adjust native_wbinvd for smp_call_function-helpers

Quoted 9 lines · H. Peter Anvin
Quoted 7 lines · Borislav Petkov

From: Borislav Petkov <[email protected]>

Add a wbinvd_on_cpu() helper and fold the void * arg in the wbinvd macro definition so that native_wbinvd can be used in the smp_call_function_* helpers as a pointed-to function.

Quoted 8 lines

This patch is a lot of extra uglification just to avoid a simple jump stub -- and even then only with PV enabled -- for an operation which is then going to perform an IPI and WBINVD. That doesn't exactly seem like the right tradeoff.

As such, I'm going to request that you just put a simple stub function in lib/smp.c rather than this whole patchset (well, the smp.h bit obviously needs to stay.)

..and I was wrapping the wrong way: wbinvd() was going to hide the void
* function argument while a simple stub in lib/smp.c could wrap around wbinvd() which is much more cleaner. Thanks.

Will redo the patchset tomorrow.

Signature · 6 lines
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center
#6 lore raw

PATCH 3/7 x86, smp: Add wbinvd_on_all_cpus helper

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

---
 arch/x86/include/asm/smp.h |    2 ++
 arch/x86/lib/smp.c         |    6 ++++++
 2 files changed, 8 insertions(+), 0 deletions(-)
arch/x86/include/asm/smp.h +2 -0
index 090146e..3c8ed3a 100644
@@ -139,6 +139,7 @@ void play_dead_common(void);
 void native_send_call_func_ipi(const struct cpumask *mask);
 void native_send_call_func_single_ipi(int cpu);
 void wbinvd_on_cpu(int cpu);
+int wbinvd_on_all_cpus(void);
 
 void smp_store_cpu_info(int id);
 #define cpu_physical_id(cpu)	per_cpu(x86_cpu_to_apicid, cpu)
@@ -150,6 +151,7 @@ static inline int num_booting_cpus(void)
 }
 #else /* !CONFIG_SMP */
 #define wbinvd_on_cpu(cpu)	wbinvd()
+#define wbinvd_on_all_cpus()	wbinvd()
 #endif /* CONFIG_SMP */
 
 extern unsigned disabled_cpus __cpuinitdata;
arch/x86/lib/smp.c +6 -0
index 408c3b7..38f92b0 100644
@@ -209,3 +209,9 @@ void wbinvd_on_cpu(int cpu)
 	smp_call_function_single(cpu, native_wbinvd, NULL, 1);
 }
 EXPORT_SYMBOL(wbinvd_on_cpu);
+
+int wbinvd_on_all_cpus(void)
+{
+	return on_each_cpu(native_wbinvd, NULL, 1);
+}
+EXPORT_SYMBOL(wbinvd_on_all_cpus);
Signature · 1 line
1.6.6
#7 lore raw

PATCH 4/7 intel-agp: Switch to wbinvd_on_all_cpus

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

---
 drivers/char/agp/intel-agp.c |    8 +-------
 1 files changed, 1 insertions(+), 7 deletions(-)
drivers/char/agp/intel-agp.c +1 -7
index 3999a5f..bc453da 100644
@@ -815,12 +815,6 @@ static void intel_i830_setup_flush(void)
 		intel_i830_fini_flush();
 }
 
-static void
-do_wbinvd(void *null)
-{
-	wbinvd();
-}
-
 /* The chipset_flush interface needs to get data that has already been
  * flushed out of the CPU all the way out to main memory, because the GPU
  * doesn't snoop those buffers.
@@ -840,7 +834,7 @@ static void intel_i830_chipset_flush(struct agp_bridge_data *bridge)
 	if (cpu_has_clflush) {
 		clflush_cache_range(pg, 1024);
 	} else {
-		if (on_each_cpu(do_wbinvd, NULL, 1) != 0)
+		if (wbinvd_on_all_cpus() != 0)
 			printk(KERN_ERR "Timed out waiting for cache flush.\n");
 	}
 }
Signature · 1 line
1.6.6
#8 lore raw

PATCH 5/7 x86, cacheinfo: Fix disabling of L3 cache indices

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

* 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

---
 arch/x86/kernel/cpu/intel_cacheinfo.c |   30 +++++++++++++++++-------------
 1 files changed, 17 insertions(+), 13 deletions(-)
arch/x86/kernel/cpu/intel_cacheinfo.c +17 -13
index fc6c8ef..cef4fdd 100644
@@ -18,6 +18,7 @@
 #include <asm/processor.h>
 #include <linux/smp.h>
 #include <asm/k8.h>
+#include <asm/smp.h>
 
 #define LVL_1_INST	1
 #define LVL_1_DATA	2
@@ -299,8 +300,10 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 	if (boot_cpu_data.x86 == 0x11)
 		return;
 
-	/* see erratum #382 */
-	if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8))
+	/* see errata #382 and #388 */
+	if ((boot_cpu_data.x86 == 0x10) &&
+	    ((boot_cpu_data.x86_model < 0x9) ||
+	     (boot_cpu_data.x86_mask  < 0x1)))
 		return;
 
 	this_leaf->can_disable = 1;
@@ -726,12 +729,12 @@ static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf,
 		return -EINVAL;
 
 	pci_read_config_dword(dev, 0x1BC + index * 4, &reg);
-	return sprintf(buf, "%x\n", reg);
+	return sprintf(buf, "0x%08x\n", reg);
 }
 
 #define SHOW_CACHE_DISABLE(index)					\
 static ssize_t								\
-show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf)  	\
+show_cache_disable_##index(struct _cpuid4_info *this_leaf, char *buf)	\
 {									\
 	return show_cache_disable(this_leaf, buf, index);		\
 }
@@ -745,7 +748,9 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 	int node = cpu_to_node(cpu);
 	struct pci_dev *dev = node_to_k8_nb_misc(node);
 	unsigned long val = 0;
-	unsigned int scrubber = 0;
+
+#define SUBCACHE_MASK	(3UL << 20)
+#define SUBCACHE_INDEX	0xfff
 
 	if (!this_leaf->can_disable)
 		return -EINVAL;
@@ -759,21 +764,20 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 	if (strict_strtoul(buf, 10, &val) < 0)
 		return -EINVAL;
 
-	val |= 0xc0000000;
-
-	pci_read_config_dword(dev, 0x58, &scrubber);
-	scrubber &= ~0x1f000000;
-	pci_write_config_dword(dev, 0x58, scrubber);
+	/* do not allow writes outside of allowed bits */
+	if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX))
+		return -EINVAL;
 
-	pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);
-	wbinvd();
+	val |= BIT(30);
 	pci_write_config_dword(dev, 0x1BC + index * 4, val);
+	wbinvd_on_cpu(cpu);
+	pci_write_config_dword(dev, 0x1BC + index * 4, val | BIT(31));
 	return count;
 }
 
 #define STORE_CACHE_DISABLE(index)					\
 static ssize_t								\
-store_cache_disable_##index(struct _cpuid4_info *this_leaf,	     	\
+store_cache_disable_##index(struct _cpuid4_info *this_leaf,		\
 			    const char *buf, size_t count)		\
 {									\
 	return store_cache_disable(this_leaf, buf, count, index);	\
Signature · 1 line
1.6.6
#9 lore raw

PATCH 6/7 x86, cacheinfo: Add cache index disable sysfs attrs only to L3 caches

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

The cache_disable_[01] attribute in

/sys/devices/system/cpu/cpu?/cache/index[0-3]/

is enabled on all cache levels although only L3 supports it. Add it only to the cache level that actually supports it.

---
 arch/x86/kernel/cpu/intel_cacheinfo.c |   35 ++++++++++++++++++++++++--------
 1 files changed, 26 insertions(+), 9 deletions(-)
arch/x86/kernel/cpu/intel_cacheinfo.c +26 -9
index cef4fdd..0ce0e8d 100644
@@ -810,16 +810,24 @@ static struct _cache_attr cache_disable_0 = __ATTR(cache_disable_0, 0644,
 static struct _cache_attr cache_disable_1 = __ATTR(cache_disable_1, 0644,
 		show_cache_disable_1, store_cache_disable_1);
 
+#define DEFAULT_SYSFS_CACHE_ATTRS	\
+	&type.attr,			\
+	&level.attr,			\
+	&coherency_line_size.attr,	\
+	&physical_line_partition.attr,	\
+	&ways_of_associativity.attr,	\
+	&number_of_sets.attr,		\
+	&size.attr,			\
+	&shared_cpu_map.attr,		\
+	&shared_cpu_list.attr
+
 static struct attribute *default_attrs[] = {
-	&type.attr,
-	&level.attr,
-	&coherency_line_size.attr,
-	&physical_line_partition.attr,
-	&ways_of_associativity.attr,
-	&number_of_sets.attr,
-	&size.attr,
-	&shared_cpu_map.attr,
-	&shared_cpu_list.attr,
+	DEFAULT_SYSFS_CACHE_ATTRS,
+	NULL
+};
+
+static struct attribute *default_l3_attrs[] = {
+	DEFAULT_SYSFS_CACHE_ATTRS,
 	&cache_disable_0.attr,
 	&cache_disable_1.attr,
 	NULL
@@ -912,6 +920,7 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
 	unsigned int cpu = sys_dev->id;
 	unsigned long i, j;
 	struct _index_kobject *this_object;
+	struct _cpuid4_info   *this_leaf;
 	int retval;
 
 	retval = cpuid4_cache_sysfs_init(cpu);
@@ -930,6 +939,14 @@ static int __cpuinit cache_add_dev(struct sys_device * sys_dev)
 		this_object = INDEX_KOBJECT_PTR(cpu, i);
 		this_object->cpu = cpu;
 		this_object->index = i;
+
+		this_leaf = CPUID4_INFO_IDX(cpu, i);
+
+		if (this_leaf->can_disable)
+			ktype_cache.default_attrs = default_l3_attrs;
+		else
+			ktype_cache.default_attrs = default_attrs;
+
 		retval = kobject_init_and_add(&(this_object->kobj),
 					      &ktype_cache,
 					      per_cpu(ici_cache_kobject, cpu),
Signature · 1 line
1.6.6
#10 lore raw

PATCH 7/7 x86, cacheinfo: Calculate L3 indexes

In reply to Borislav Petkov

From: Borislav Petkov <[email protected]>

We need to know the valid L3 indexes interval when disabling them over /sysfs. Do that when the core is brought online and add boundary checks to the sysfs .store attribute.

---
 arch/x86/kernel/cpu/intel_cacheinfo.c |   35 +++++++++++++++++++++++++++++---
 1 files changed, 31 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/intel_cacheinfo.c +31 -4
index 0ce0e8d..d231c38 100644
@@ -151,7 +151,8 @@ struct _cpuid4_info {
 	union _cpuid4_leaf_ebx ebx;
 	union _cpuid4_leaf_ecx ecx;
 	unsigned long size;
-	unsigned long can_disable;
+	bool can_disable;
+	unsigned int l3_indices;
 	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
 };
 
@@ -161,7 +162,8 @@ struct _cpuid4_info_regs {
 	union _cpuid4_leaf_ebx ebx;
 	union _cpuid4_leaf_ecx ecx;
 	unsigned long size;
-	unsigned long can_disable;
+	bool can_disable;
+	unsigned int l3_indices;
 };
 
 unsigned short			num_cache_leaves;
@@ -291,6 +293,29 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
+static unsigned int __cpuinit amd_calc_l3_indices(void)
+{
+	/*
+	 * We're called over smp_call_function_single() and therefore
+	 * are on the correct cpu.
+	 */
+	int cpu = smp_processor_id();
+	int node = cpu_to_node(cpu);
+	struct pci_dev *dev = node_to_k8_nb_misc(node);
+	unsigned int sc0, sc1, sc2, sc3;
+	u32 val;
+
+	pci_read_config_dword(dev, 0x1C4, &val);
+
+	/* calculate subcache sizes */
+	sc0 = !(val & BIT(0));
+	sc1 = !(val & BIT(4));
+	sc2 = !(val & BIT(8))  + !(val & BIT(9));
+	sc3 = !(val & BIT(12)) + !(val & BIT(13));
+
+	return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+}
+
 static void __cpuinit
 amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 {
@@ -306,7 +331,8 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 	     (boot_cpu_data.x86_mask  < 0x1)))
 		return;
 
-	this_leaf->can_disable = 1;
+	this_leaf->can_disable = true;
+	this_leaf->l3_indices  = amd_calc_l3_indices();
 }
 
 static int
@@ -765,7 +791,8 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 		return -EINVAL;
 
 	/* do not allow writes outside of allowed bits */
-	if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX))
+	if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
+	    ((val & SUBCACHE_INDEX) > this_leaf->l3_indices))
 		return -EINVAL;
 
 	val |= BIT(30);
Signature · 1 line
1.6.6
#11 lore raw

PATCH 1/1 x86, cacheinfo: Calculate L3 indices

From: Borislav Petkov <[email protected]>

We need to know the valid L3 indices interval when disabling them over /sysfs. Do that when the core is brought online and add boundary checks to the sysfs .store attribute.

---
Fix indexes -> indices in the commit message.

 arch/x86/kernel/cpu/intel_cacheinfo.c |   35 +++++++++++++++++++++++++++++---
 1 files changed, 31 insertions(+), 4 deletions(-)
arch/x86/kernel/cpu/intel_cacheinfo.c +31 -4
index 0ce0e8d..d231c38 100644
@@ -151,7 +151,8 @@ struct _cpuid4_info {
 	union _cpuid4_leaf_ebx ebx;
 	union _cpuid4_leaf_ecx ecx;
 	unsigned long size;
-	unsigned long can_disable;
+	bool can_disable;
+	unsigned int l3_indices;
 	DECLARE_BITMAP(shared_cpu_map, NR_CPUS);
 };
 
@@ -161,7 +162,8 @@ struct _cpuid4_info_regs {
 	union _cpuid4_leaf_ebx ebx;
 	union _cpuid4_leaf_ecx ecx;
 	unsigned long size;
-	unsigned long can_disable;
+	bool can_disable;
+	unsigned int l3_indices;
 };
 
 unsigned short			num_cache_leaves;
@@ -291,6 +293,29 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,
 		(ebx->split.ways_of_associativity + 1) - 1;
 }
 
+static unsigned int __cpuinit amd_calc_l3_indices(void)
+{
+	/*
+	 * We're called over smp_call_function_single() and therefore
+	 * are on the correct cpu.
+	 */
+	int cpu = smp_processor_id();
+	int node = cpu_to_node(cpu);
+	struct pci_dev *dev = node_to_k8_nb_misc(node);
+	unsigned int sc0, sc1, sc2, sc3;
+	u32 val;
+
+	pci_read_config_dword(dev, 0x1C4, &val);
+
+	/* calculate subcache sizes */
+	sc0 = !(val & BIT(0));
+	sc1 = !(val & BIT(4));
+	sc2 = !(val & BIT(8))  + !(val & BIT(9));
+	sc3 = !(val & BIT(12)) + !(val & BIT(13));
+
+	return (max(max(max(sc0, sc1), sc2), sc3) << 10) - 1;
+}
+
 static void __cpuinit
 amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 {
@@ -306,7 +331,8 @@ amd_check_l3_disable(int index, struct _cpuid4_info_regs *this_leaf)
 	     (boot_cpu_data.x86_mask  < 0x1)))
 		return;
 
-	this_leaf->can_disable = 1;
+	this_leaf->can_disable = true;
+	this_leaf->l3_indices  = amd_calc_l3_indices();
 }
 
 static int
@@ -765,7 +791,8 @@ static ssize_t store_cache_disable(struct _cpuid4_info *this_leaf,
 		return -EINVAL;
 
 	/* do not allow writes outside of allowed bits */
-	if (val & ~(SUBCACHE_MASK | SUBCACHE_INDEX))
+	if ((val & ~(SUBCACHE_MASK | SUBCACHE_INDEX)) ||
+	    ((val & SUBCACHE_INDEX) > this_leaf->l3_indices))
 		return -EINVAL;
 
 	val |= BIT(30);
Signature · 9 lines
1.6.6

-- 
Regards/Gruss,
Boris.

-
Advanced Micro Devices, Inc.
Operating Systems Research Center