diff options
Diffstat (limited to 'drivers/acpi/pci_root.c')
| -rw-r--r-- | drivers/acpi/pci_root.c | 97 | 
1 files changed, 56 insertions, 41 deletions
| diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index 1f67057af2a..3ba8d1f44a7 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -33,7 +33,6 @@  #include <linux/pm_runtime.h>  #include <linux/pci.h>  #include <linux/pci-acpi.h> -#include <linux/pci-aspm.h>  #include <linux/acpi.h>  #include <linux/slab.h>  #include <acpi/acpi_bus.h> @@ -226,22 +225,31 @@ static acpi_status acpi_pci_run_osc(acpi_handle handle,  	return status;  } -static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, u32 flags) +static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root, +					u32 support, +					u32 *control)  {  	acpi_status status; -	u32 support_set, result, capbuf[3]; +	u32 result, capbuf[3]; + +	support &= OSC_PCI_SUPPORT_MASKS; +	support |= root->osc_support_set; -	/* do _OSC query for all possible controls */ -	support_set = root->osc_support_set | (flags & OSC_PCI_SUPPORT_MASKS);  	capbuf[OSC_QUERY_TYPE] = OSC_QUERY_ENABLE; -	capbuf[OSC_SUPPORT_TYPE] = support_set; -	capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; +	capbuf[OSC_SUPPORT_TYPE] = support; +	if (control) { +		*control &= OSC_PCI_CONTROL_MASKS; +		capbuf[OSC_CONTROL_TYPE] = *control | root->osc_control_set; +	} else { +		/* Run _OSC query for all possible controls. */ +		capbuf[OSC_CONTROL_TYPE] = OSC_PCI_CONTROL_MASKS; +	}  	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);  	if (ACPI_SUCCESS(status)) { -		root->osc_support_set = support_set; -		root->osc_control_qry = result; -		root->osc_queried = 1; +		root->osc_support_set = support; +		if (control) +			*control = result;  	}  	return status;  } @@ -255,7 +263,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)  	if (ACPI_FAILURE(status))  		return status;  	mutex_lock(&osc_lock); -	status = acpi_pci_query_osc(root, flags); +	status = acpi_pci_query_osc(root, flags, NULL);  	mutex_unlock(&osc_lock);  	return status;  } @@ -365,55 +373,70 @@ out:  EXPORT_SYMBOL_GPL(acpi_get_pci_dev);  /** - * acpi_pci_osc_control_set - commit requested control to Firmware - * @handle: acpi_handle for the target ACPI object - * @flags: driver's requested control bits + * acpi_pci_osc_control_set - Request control of PCI root _OSC features. + * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex). + * @mask: Mask of _OSC bits to request control of, place to store control mask. + * @req: Mask of _OSC bits the control of is essential to the caller. + * + * Run _OSC query for @mask and if that is successful, compare the returned + * mask of control bits with @req.  If all of the @req bits are set in the + * returned mask, run _OSC request for it.   * - * Attempt to take control from Firmware on requested control bits. + * The variable at the @mask address may be modified regardless of whether or + * not the function returns success.  On success it will contain the mask of + * _OSC bits the BIOS has granted control of, but its contents are meaningless + * on failure.   **/ -acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) +acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)  { +	struct acpi_pci_root *root;  	acpi_status status; -	u32 control_req, result, capbuf[3]; +	u32 ctrl, capbuf[3];  	acpi_handle tmp; -	struct acpi_pci_root *root; -	status = acpi_get_handle(handle, "_OSC", &tmp); -	if (ACPI_FAILURE(status)) -		return status; +	if (!mask) +		return AE_BAD_PARAMETER; -	control_req = (flags & OSC_PCI_CONTROL_MASKS); -	if (!control_req) +	ctrl = *mask & OSC_PCI_CONTROL_MASKS; +	if ((ctrl & req) != req)  		return AE_TYPE;  	root = acpi_pci_find_root(handle);  	if (!root)  		return AE_NOT_EXIST; +	status = acpi_get_handle(handle, "_OSC", &tmp); +	if (ACPI_FAILURE(status)) +		return status; +  	mutex_lock(&osc_lock); + +	*mask = ctrl | root->osc_control_set;  	/* No need to evaluate _OSC if the control was already granted. */ -	if ((root->osc_control_set & control_req) == control_req) +	if ((root->osc_control_set & ctrl) == ctrl)  		goto out; -	/* Need to query controls first before requesting them */ -	if (!root->osc_queried) { -		status = acpi_pci_query_osc(root, root->osc_support_set); +	/* Need to check the available controls bits before requesting them. */ +	while (*mask) { +		status = acpi_pci_query_osc(root, root->osc_support_set, mask);  		if (ACPI_FAILURE(status))  			goto out; +		if (ctrl == *mask) +			break; +		ctrl = *mask;  	} -	if ((root->osc_control_qry & control_req) != control_req) { -		printk(KERN_DEBUG -		       "Firmware did not grant requested _OSC control\n"); + +	if ((ctrl & req) != req) {  		status = AE_SUPPORT;  		goto out;  	}  	capbuf[OSC_QUERY_TYPE] = 0;  	capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set; -	capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req; -	status = acpi_pci_run_osc(handle, capbuf, &result); +	capbuf[OSC_CONTROL_TYPE] = ctrl; +	status = acpi_pci_run_osc(handle, capbuf, mask);  	if (ACPI_SUCCESS(status)) -		root->osc_control_set = result; +		root->osc_control_set = *mask;  out:  	mutex_unlock(&osc_lock);  	return status; @@ -544,14 +567,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)  	if (flags != base_flags)  		acpi_pci_osc_support(root, flags); -	status = acpi_pci_osc_control_set(root->device->handle, -					  OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); - -	if (ACPI_FAILURE(status)) { -		printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); -		pcie_no_aspm(); -	} -  	pci_acpi_add_bus_pm_notifier(device, root->bus);  	if (device->wakeup.flags.run_wake)  		device_set_run_wake(root->bus->bridge, true); | 
