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 483eda96e10..789efe217e1 100644 --- a/arch/x86/kernel/cpu/intel_cacheinfo.c +++ b/arch/x86/kernel/cpu/intel_cacheinfo.c @@ -17,6 +17,7 @@  #include <asm/processor.h>  #include <asm/smp.h> +#include <asm/k8.h>  #define LVL_1_INST	1  #define LVL_1_DATA	2 @@ -159,14 +160,6 @@ struct _cpuid4_info_regs {  	unsigned long can_disable;  }; -#if defined(CONFIG_PCI) && defined(CONFIG_SYSFS) -static struct pci_device_id k8_nb_id[] = { -	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1103) }, -	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, 0x1203) }, -	{} -}; -#endif -  unsigned short			num_cache_leaves;  /* AMD doesn't have CPUID4. Emulate it here to report the same @@ -207,10 +200,17 @@ union l3_cache {  };  static const unsigned short __cpuinitconst assocs[] = { -	[1] = 1, [2] = 2, [4] = 4, [6] = 8, -	[8] = 16, [0xa] = 32, [0xb] = 48, +	[1] = 1, +	[2] = 2, +	[4] = 4, +	[6] = 8, +	[8] = 16, +	[0xa] = 32, +	[0xb] = 48,  	[0xc] = 64, -	[0xf] = 0xffff // ?? +	[0xd] = 96, +	[0xe] = 128, +	[0xf] = 0xffff /* fully associative - no way to show this currently */  };  static const unsigned char __cpuinitconst levels[] = { 1, 1, 2, 3 }; @@ -271,7 +271,8 @@ amd_cpuid4(int leaf, union _cpuid4_leaf_eax *eax,  	eax->split.type = types[leaf];  	eax->split.level = levels[leaf];  	if (leaf == 3) -		eax->split.num_threads_sharing = current_cpu_data.x86_max_cores - 1; +		eax->split.num_threads_sharing = +			current_cpu_data.x86_max_cores - 1;  	else  		eax->split.num_threads_sharing = 0;  	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)  {  	if (index < 3)  		return; + +	if (boot_cpu_data.x86 == 0x11) +		return; + +	/* see erratum #382 */ +	if ((boot_cpu_data.x86 == 0x10) && (boot_cpu_data.x86_model < 0x8)) +		return; +  	this_leaf->can_disable = 1;  } @@ -696,97 +705,75 @@ 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) -#ifdef CONFIG_PCI -static struct pci_dev *get_k8_northbridge(int node) -{ -	struct pci_dev *dev = NULL; -	int i; - -	for (i = 0; i <= node; i++) { -		do { -			dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); -			if (!dev) -				break; -		} while (!pci_match_id(&k8_nb_id[0], dev)); -		if (!dev) -			break; -	} -	return dev; -} -#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) +static ssize_t show_cache_disable(struct _cpuid4_info *this_leaf, char *buf, +				  unsigned int index)  { -	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); -	int node = cpu_to_node(cpumask_first(mask)); -	struct pci_dev *dev = NULL; -	ssize_t ret = 0; -	int i; +	int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); +	int node = cpu_to_node(cpu); +	struct pci_dev *dev = node_to_k8_nb_misc(node); +	unsigned int reg = 0;  	if (!this_leaf->can_disable) -		return sprintf(buf, "Feature not enabled\n"); - -	dev = get_k8_northbridge(node); -	if (!dev) { -		printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n");  		return -EINVAL; -	} -	for (i = 0; i < 2; i++) { -		unsigned int reg; +	if (!dev) +		return -EINVAL; -		pci_read_config_dword(dev, 0x1BC + i * 4, ®); +	pci_read_config_dword(dev, 0x1BC + index * 4, ®); +	return sprintf(buf, "%x\n", 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; +#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);		\  } +SHOW_CACHE_DISABLE(0) +SHOW_CACHE_DISABLE(1) -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, unsigned int index)  { -	const struct cpumask *mask = to_cpumask(this_leaf->shared_cpu_map); -	int node = cpu_to_node(cpumask_first(mask)); -	struct pci_dev *dev = NULL; -	unsigned int ret, index, val; +	int cpu = cpumask_first(to_cpumask(this_leaf->shared_cpu_map)); +	int node = cpu_to_node(cpu); +	struct pci_dev *dev = node_to_k8_nb_misc(node); +	unsigned long val = 0; +	unsigned int scrubber = 0;  	if (!this_leaf->can_disable) -		return 0; - -	if (strlen(buf) > 15)  		return -EINVAL; -	ret = sscanf(buf, "%x %x", &index, &val); -	if (ret != 2) +	if (!capable(CAP_SYS_ADMIN)) +		return -EPERM; + +	if (!dev)  		return -EINVAL; -	if (index > 1) + +	if (strict_strtoul(buf, 10, &val) < 0)  		return -EINVAL;  	val |= 0xc0000000; -	dev = get_k8_northbridge(node); -	if (!dev) { -		printk(KERN_ERR "Attempting AMD northbridge operation on a system with no northbridge\n"); -		return -EINVAL; -	} + +	pci_read_config_dword(dev, 0x58, &scrubber); +	scrubber &= ~0x1f000000; +	pci_write_config_dword(dev, 0x58, scrubber);  	pci_write_config_dword(dev, 0x1BC + index * 4, val & ~0x40000000);  	wbinvd();  	pci_write_config_dword(dev, 0x1BC + index * 4, val); +	return count; +} -	return 1; +#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);	\  } +STORE_CACHE_DISABLE(0) +STORE_CACHE_DISABLE(1)  struct _cache_attr {  	struct attribute attr; @@ -808,7 +795,10 @@ 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 _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, @@ -820,7 +810,8 @@ static struct attribute * default_attrs[] = {  	&size.attr,  	&shared_cpu_map.attr,  	&shared_cpu_list.attr, -	&cache_disable.attr, +	&cache_disable_0.attr, +	&cache_disable_1.attr,  	NULL  };  |