diff options
Diffstat (limited to 'arch/x86/pci/acpi.c')
| -rw-r--r-- | arch/x86/pci/acpi.c | 109 | 
1 files changed, 95 insertions, 14 deletions
diff --git a/arch/x86/pci/acpi.c b/arch/x86/pci/acpi.c index fc09c2754e0..505acdd6d60 100644 --- a/arch/x86/pci/acpi.c +++ b/arch/x86/pci/acpi.c @@ -12,8 +12,13 @@ struct pci_root_info {  	char name[16];  	unsigned int res_num;  	struct resource *res; -	int busnum;  	struct pci_sysdata sd; +#ifdef	CONFIG_PCI_MMCONFIG +	bool mcfg_added; +	u16 segment; +	u8 start_bus; +	u8 end_bus; +#endif  };  static bool pci_use_crs = true; @@ -120,6 +125,81 @@ void __init pci_acpi_crs_quirks(void)  	       pci_use_crs ? "nocrs" : "use_crs");  } +#ifdef	CONFIG_PCI_MMCONFIG +static int __devinit check_segment(u16 seg, struct device *dev, char *estr) +{ +	if (seg) { +		dev_err(dev, +			"%s can't access PCI configuration " +			"space under this host bridge.\n", +			estr); +		return -EIO; +	} + +	/* +	 * Failure in adding MMCFG information is not fatal, +	 * just can't access extended configuration space of +	 * devices under this host bridge. +	 */ +	dev_warn(dev, +		 "%s can't access extended PCI configuration " +		 "space under this bridge.\n", +		 estr); + +	return 0; +} + +static int __devinit setup_mcfg_map(struct pci_root_info *info, +				    u16 seg, u8 start, u8 end, +				    phys_addr_t addr) +{ +	int result; +	struct device *dev = &info->bridge->dev; + +	info->start_bus = start; +	info->end_bus = end; +	info->mcfg_added = false; + +	/* return success if MMCFG is not in use */ +	if (raw_pci_ext_ops && raw_pci_ext_ops != &pci_mmcfg) +		return 0; + +	if (!(pci_probe & PCI_PROBE_MMCONF)) +		return check_segment(seg, dev, "MMCONFIG is disabled,"); + +	result = pci_mmconfig_insert(dev, seg, start, end, addr); +	if (result == 0) { +		/* enable MMCFG if it hasn't been enabled yet */ +		if (raw_pci_ext_ops == NULL) +			raw_pci_ext_ops = &pci_mmcfg; +		info->mcfg_added = true; +	} else if (result != -EEXIST) +		return check_segment(seg, dev, +			 "fail to add MMCONFIG information,"); + +	return 0; +} + +static void teardown_mcfg_map(struct pci_root_info *info) +{ +	if (info->mcfg_added) { +		pci_mmconfig_delete(info->segment, info->start_bus, +				    info->end_bus); +		info->mcfg_added = false; +	} +} +#else +static int __devinit setup_mcfg_map(struct pci_root_info *info, +				    u16 seg, u8 start, u8 end, +				    phys_addr_t addr) +{ +	return 0; +} +static void teardown_mcfg_map(struct pci_root_info *info) +{ +} +#endif +  static acpi_status  resource_to_addr(struct acpi_resource *resource,  			struct acpi_resource_address64 *addr) @@ -234,13 +314,6 @@ setup_resource(struct acpi_resource *acpi_res, void *data)  	}  	info->res_num++; -	if (addr.translation_offset) -		dev_info(&info->bridge->dev, "host bridge window %pR " -			 "(PCI address [%#llx-%#llx])\n", -			 res, res->start - addr.translation_offset, -			 res->end - addr.translation_offset); -	else -		dev_info(&info->bridge->dev, "host bridge window %pR\n", res);  	return AE_OK;  } @@ -332,8 +405,11 @@ static void __release_pci_root_info(struct pci_root_info *info)  	free_pci_root_info_res(info); +	teardown_mcfg_map(info); +  	kfree(info);  } +  static void release_pci_root_info(struct pci_host_bridge *bridge)  {  	struct pci_root_info *info = bridge->release_data; @@ -347,7 +423,9 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,  {  	size_t size; +	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum);  	info->bridge = device; +  	info->res_num = 0;  	acpi_walk_resources(device->handle, METHOD_NAME__CRS, count_resource,  				info); @@ -360,8 +438,6 @@ probe_pci_root_info(struct pci_root_info *info, struct acpi_device *device,  	if (!info->res)  		return; -	sprintf(info->name, "PCI Bus %04x:%02x", domain, busnum); -  	acpi_walk_resources(device->handle, METHOD_NAME__CRS, setup_resource,  				info);  } @@ -373,7 +449,7 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)  	int domain = root->segment;  	int busnum = root->secondary.start;  	LIST_HEAD(resources); -	struct pci_bus *bus; +	struct pci_bus *bus = NULL;  	struct pci_sysdata *sd;  	int node;  #ifdef CONFIG_ACPI_NUMA @@ -426,6 +502,8 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)  	} else {  		probe_pci_root_info(info, device, busnum, domain); +		/* insert busn res at first */ +		pci_add_resource(&resources,  &root->secondary);  		/*  		 * _CRS with no apertures is normal, so only fall back to  		 * defaults or native bridge info if we're ignoring _CRS. @@ -437,10 +515,13 @@ struct pci_bus * __devinit pci_acpi_scan_root(struct acpi_pci_root *root)  			x86_pci_root_bus_resources(busnum, &resources);  		} -		bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, sd, -					  &resources); +		if (!setup_mcfg_map(info, domain, (u8)root->secondary.start, +				    (u8)root->secondary.end, root->mcfg_addr)) +			bus = pci_create_root_bus(NULL, busnum, &pci_root_ops, +						  sd, &resources); +  		if (bus) { -			bus->subordinate = pci_scan_child_bus(bus); +			pci_scan_child_bus(bus);  			pci_set_host_bridge_release(  				to_pci_host_bridge(bus->bridge),  				release_pci_root_info, info);  |