diff options
Diffstat (limited to 'arch/x86/kernel/amd_nb.c')
| -rw-r--r-- | arch/x86/kernel/amd_nb.c | 100 | 
1 files changed, 88 insertions, 12 deletions
diff --git a/arch/x86/kernel/amd_nb.c b/arch/x86/kernel/amd_nb.c index 0a99f7198bc3..65634190ffd6 100644 --- a/arch/x86/kernel/amd_nb.c +++ b/arch/x86/kernel/amd_nb.c @@ -12,7 +12,7 @@  static u32 *flush_words; -struct pci_device_id amd_nb_misc_ids[] = { +const struct pci_device_id amd_nb_misc_ids[] = {  	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_K8_NB_MISC) },  	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_10H_NB_MISC) },  	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_MISC) }, @@ -20,6 +20,11 @@ struct pci_device_id amd_nb_misc_ids[] = {  };  EXPORT_SYMBOL(amd_nb_misc_ids); +static struct pci_device_id amd_nb_link_ids[] = { +	{ PCI_DEVICE(PCI_VENDOR_ID_AMD, PCI_DEVICE_ID_AMD_15H_NB_LINK) }, +	{} +}; +  const struct amd_nb_bus_dev_range amd_nb_bus_dev_ranges[] __initconst = {  	{ 0x00, 0x18, 0x20 },  	{ 0xff, 0x00, 0x20 }, @@ -31,7 +36,7 @@ struct amd_northbridge_info amd_northbridges;  EXPORT_SYMBOL(amd_northbridges);  static struct pci_dev *next_northbridge(struct pci_dev *dev, -					struct pci_device_id *ids) +					const struct pci_device_id *ids)  {  	do {  		dev = pci_get_device(PCI_ANY_ID, PCI_ANY_ID, dev); @@ -43,9 +48,9 @@ static struct pci_dev *next_northbridge(struct pci_dev *dev,  int amd_cache_northbridges(void)  { -	int i = 0; +	u16 i = 0;  	struct amd_northbridge *nb; -	struct pci_dev *misc; +	struct pci_dev *misc, *link;  	if (amd_nb_num())  		return 0; @@ -64,10 +69,12 @@ int amd_cache_northbridges(void)  	amd_northbridges.nb = nb;  	amd_northbridges.num = i; -	misc = NULL; +	link = misc = NULL;  	for (i = 0; i != amd_nb_num(); i++) {  		node_to_amd_nb(i)->misc = misc =  			next_northbridge(misc, amd_nb_misc_ids); +		node_to_amd_nb(i)->link = link = +			next_northbridge(link, amd_nb_link_ids);          }  	/* some CPU families (e.g. family 0x11) do not support GART */ @@ -85,26 +92,95 @@ int amd_cache_northbridges(void)  	     boot_cpu_data.x86_mask >= 0x1))  		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE; +	if (boot_cpu_data.x86 == 0x15) +		amd_northbridges.flags |= AMD_NB_L3_INDEX_DISABLE; + +	/* L3 cache partitioning is supported on family 0x15 */ +	if (boot_cpu_data.x86 == 0x15) +		amd_northbridges.flags |= AMD_NB_L3_PARTITIONING; +  	return 0;  }  EXPORT_SYMBOL_GPL(amd_cache_northbridges); -/* Ignores subdevice/subvendor but as far as I can figure out -   they're useless anyways */ -int __init early_is_amd_nb(u32 device) +/* + * Ignores subdevice/subvendor but as far as I can figure out + * they're useless anyways + */ +bool __init early_is_amd_nb(u32 device)  { -	struct pci_device_id *id; +	const struct pci_device_id *id;  	u32 vendor = device & 0xffff; +  	device >>= 16;  	for (id = amd_nb_misc_ids; id->vendor; id++)  		if (vendor == id->vendor && device == id->device) -			return 1; +			return true; +	return false; +} + +int amd_get_subcaches(int cpu) +{ +	struct pci_dev *link = node_to_amd_nb(amd_get_nb_id(cpu))->link; +	unsigned int mask; +	int cuid = 0; + +	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING)) +		return 0; + +	pci_read_config_dword(link, 0x1d4, &mask); + +#ifdef CONFIG_SMP +	cuid = cpu_data(cpu).compute_unit_id; +#endif +	return (mask >> (4 * cuid)) & 0xf; +} + +int amd_set_subcaches(int cpu, int mask) +{ +	static unsigned int reset, ban; +	struct amd_northbridge *nb = node_to_amd_nb(amd_get_nb_id(cpu)); +	unsigned int reg; +	int cuid = 0; + +	if (!amd_nb_has_feature(AMD_NB_L3_PARTITIONING) || mask > 0xf) +		return -EINVAL; + +	/* if necessary, collect reset state of L3 partitioning and BAN mode */ +	if (reset == 0) { +		pci_read_config_dword(nb->link, 0x1d4, &reset); +		pci_read_config_dword(nb->misc, 0x1b8, &ban); +		ban &= 0x180000; +	} + +	/* deactivate BAN mode if any subcaches are to be disabled */ +	if (mask != 0xf) { +		pci_read_config_dword(nb->misc, 0x1b8, ®); +		pci_write_config_dword(nb->misc, 0x1b8, reg & ~0x180000); +	} + +#ifdef CONFIG_SMP +	cuid = cpu_data(cpu).compute_unit_id; +#endif +	mask <<= 4 * cuid; +	mask |= (0xf ^ (1 << cuid)) << 26; + +	pci_write_config_dword(nb->link, 0x1d4, mask); + +	/* reset BAN mode if L3 partitioning returned to reset state */ +	pci_read_config_dword(nb->link, 0x1d4, ®); +	if (reg == reset) { +		pci_read_config_dword(nb->misc, 0x1b8, ®); +		reg &= ~0x180000; +		pci_write_config_dword(nb->misc, 0x1b8, reg | ban); +	} +  	return 0;  } -int amd_cache_gart(void) +static int amd_cache_gart(void)  { -       int i; +	u16 i;         if (!amd_nb_has_feature(AMD_NB_GART))                 return 0;  | 
