diff options
Diffstat (limited to 'arch/x86/pci/amd_bus.c')
| -rw-r--r-- | arch/x86/pci/amd_bus.c | 98 | 
1 files changed, 58 insertions, 40 deletions
diff --git a/arch/x86/pci/amd_bus.c b/arch/x86/pci/amd_bus.c index a48be98e9de..c20d2cc7ef6 100644 --- a/arch/x86/pci/amd_bus.c +++ b/arch/x86/pci/amd_bus.c @@ -11,27 +11,33 @@  #include "bus_numa.h" -/* - * This discovers the pcibus <-> node mapping on AMD K8. - * also get peer root bus resource for io,mmio - */ +#define AMD_NB_F0_NODE_ID			0x60 +#define AMD_NB_F0_UNIT_ID			0x64 +#define AMD_NB_F1_CONFIG_MAP_REG		0xe0 + +#define RANGE_NUM				16 +#define AMD_NB_F1_CONFIG_MAP_RANGES		4 -struct pci_hostbridge_probe { +struct amd_hostbridge {  	u32 bus;  	u32 slot; -	u32 vendor;  	u32 device;  }; -static struct pci_hostbridge_probe pci_probes[] __initdata = { -	{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1100 }, -	{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1200 }, -	{ 0xff, 0, PCI_VENDOR_ID_AMD, 0x1200 }, -	{ 0, 0x18, PCI_VENDOR_ID_AMD, 0x1300 }, +/* + * IMPORTANT NOTE: + * hb_probes[] and early_root_info_init() is in maintenance mode. + * It only supports K8, Fam10h, Fam11h, and Fam15h_00h-0fh . + * Future processor will rely on information in ACPI. + */ +static struct amd_hostbridge hb_probes[] __initdata = { +	{ 0, 0x18, 0x1100 }, /* K8 */ +	{ 0, 0x18, 0x1200 }, /* Family10h */ +	{ 0xff, 0, 0x1200 }, /* Family10h */ +	{ 0, 0x18, 0x1300 }, /* Family11h */ +	{ 0, 0x18, 0x1600 }, /* Family15h */  }; -#define RANGE_NUM 16 -  static struct pci_root_info __init *find_pci_root_info(int node, int link)  {  	struct pci_root_info *info; @@ -44,22 +50,13 @@ static struct pci_root_info __init *find_pci_root_info(int node, int link)  	return NULL;  } -static void __init set_mp_bus_range_to_node(int min_bus, int max_bus, int node) -{ -#ifdef CONFIG_NUMA -	int j; - -	for (j = min_bus; j <= max_bus; j++) -		set_mp_bus_to_node(j, node); -#endif -}  /** - * early_fill_mp_bus_to_node() + * early_root_info_init()   * called before pcibios_scan_root and pci_scan_bus - * fills the mp_bus_to_cpumask array based according to the LDT Bus Number - * Registers found in the K8 northbridge + * fills the mp_bus_to_cpumask array based according + * to the LDT Bus Number Registers found in the northbridge.   */ -static int __init early_fill_mp_bus_info(void) +static int __init early_root_info_init(void)  {  	int i;  	unsigned bus; @@ -84,19 +81,21 @@ static int __init early_fill_mp_bus_info(void)  		return -1;  	found = false; -	for (i = 0; i < ARRAY_SIZE(pci_probes); i++) { +	for (i = 0; i < ARRAY_SIZE(hb_probes); i++) {  		u32 id;  		u16 device;  		u16 vendor; -		bus = pci_probes[i].bus; -		slot = pci_probes[i].slot; +		bus = hb_probes[i].bus; +		slot = hb_probes[i].slot;  		id = read_pci_config(bus, slot, 0, PCI_VENDOR_ID); -  		vendor = id & 0xffff;  		device = (id>>16) & 0xffff; -		if (pci_probes[i].vendor == vendor && -		    pci_probes[i].device == device) { + +		if (vendor != PCI_VENDOR_ID_AMD) +			continue; + +		if (hb_probes[i].device == device) {  			found = true;  			break;  		} @@ -105,10 +104,16 @@ static int __init early_fill_mp_bus_info(void)  	if (!found)  		return 0; -	for (i = 0; i < 4; i++) { +	/* +	 * We should learn topology and routing information from _PXM and +	 * _CRS methods in the ACPI namespace.  We extract node numbers +	 * here to work around BIOSes that don't supply _PXM. +	 */ +	for (i = 0; i < AMD_NB_F1_CONFIG_MAP_RANGES; i++) {  		int min_bus;  		int max_bus; -		reg = read_pci_config(bus, slot, 1, 0xe0 + (i << 2)); +		reg = read_pci_config(bus, slot, 1, +				AMD_NB_F1_CONFIG_MAP_REG + (i << 2));  		/* Check if that register is enabled for bus range */  		if ((reg & 7) != 3) @@ -117,16 +122,26 @@ static int __init early_fill_mp_bus_info(void)  		min_bus = (reg >> 16) & 0xff;  		max_bus = (reg >> 24) & 0xff;  		node = (reg >> 4) & 0x07; -		set_mp_bus_range_to_node(min_bus, max_bus, node);  		link = (reg >> 8) & 0x03;  		info = alloc_pci_root_info(min_bus, max_bus, node, link);  	} +	/* +	 * The following code extracts routing information for use on old +	 * systems where Linux doesn't automatically use host bridge _CRS +	 * methods (or when the user specifies "pci=nocrs"). +	 * +	 * We only do this through Fam11h, because _CRS should be enough on +	 * newer systems. +	 */ +	if (boot_cpu_data.x86 > 0x11) +		return 0; +  	/* get the default node and link for left over res */ -	reg = read_pci_config(bus, slot, 0, 0x60); +	reg = read_pci_config(bus, slot, 0, AMD_NB_F0_NODE_ID);  	def_node = (reg >> 8) & 0x07; -	reg = read_pci_config(bus, slot, 0, 0x64); +	reg = read_pci_config(bus, slot, 0, AMD_NB_F0_UNIT_ID);  	def_link = (reg >> 8) & 0x03;  	memset(range, 0, sizeof(range)); @@ -373,17 +388,20 @@ static int __init pci_io_ecs_init(void)  	int cpu;  	/* assume all cpus from fam10h have IO ECS */ -        if (boot_cpu_data.x86 < 0x10) +	if (boot_cpu_data.x86 < 0x10)  		return 0;  	/* Try the PCI method first. */  	if (early_pci_allowed())  		pci_enable_pci_io_ecs(); -	register_cpu_notifier(&amd_cpu_notifier); +	cpu_notifier_register_begin();  	for_each_online_cpu(cpu)  		amd_cpu_notify(&amd_cpu_notifier, (unsigned long)CPU_ONLINE,  			       (void *)(long)cpu); +	__register_cpu_notifier(&amd_cpu_notifier); +	cpu_notifier_register_done(); +  	pci_probe |= PCI_HAS_IO_ECS;  	return 0; @@ -394,7 +412,7 @@ static int __init amd_postcore_init(void)  	if (boot_cpu_data.x86_vendor != X86_VENDOR_AMD)  		return 0; -	early_fill_mp_bus_info(); +	early_root_info_init();  	pci_io_ecs_init();  	return 0;  | 
