diff options
Diffstat (limited to 'drivers/acpi/pci_root.c')
| -rw-r--r-- | drivers/acpi/pci_root.c | 161 | 
1 files changed, 84 insertions, 77 deletions
| diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c index d7deedf3548e..ab2f7dfb0c44 100644 --- a/drivers/acpi/pci_root.c +++ b/drivers/acpi/pci_root.c @@ -199,33 +199,20 @@ static acpi_status acpi_pci_query_osc(struct acpi_pci_root *root,  	acpi_status status;  	u32 result, capbuf[3]; -	support &= OSC_PCI_SUPPORT_MASKS;  	support |= root->osc_support_set;  	capbuf[OSC_QUERY_DWORD] = OSC_QUERY_ENABLE;  	capbuf[OSC_SUPPORT_DWORD] = support; -	if (control) { -		*control &= OSC_PCI_CONTROL_MASKS; -		capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set; -	} else { -		/* Run _OSC query only with existing controls. */ -		capbuf[OSC_CONTROL_DWORD] = root->osc_control_set; -	} +	capbuf[OSC_CONTROL_DWORD] = *control | root->osc_control_set;  	status = acpi_pci_run_osc(root->device->handle, capbuf, &result);  	if (ACPI_SUCCESS(status)) {  		root->osc_support_set = support; -		if (control) -			*control = result; +		*control = result;  	}  	return status;  } -static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags) -{ -	return acpi_pci_query_osc(root, flags, NULL); -} -  struct acpi_pci_root *acpi_pci_find_root(acpi_handle handle)  {  	struct acpi_pci_root *root; @@ -348,8 +335,9 @@ EXPORT_SYMBOL_GPL(acpi_get_pci_dev);   * _OSC bits the BIOS has granted control of, but its contents are meaningless   * on failure.   **/ -static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req) +static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 support)  { +	u32 req = OSC_PCI_EXPRESS_CAPABILITY_CONTROL;  	struct acpi_pci_root *root;  	acpi_status status;  	u32 ctrl, capbuf[3]; @@ -357,22 +345,16 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r  	if (!mask)  		return AE_BAD_PARAMETER; -	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; -	*mask = ctrl | root->osc_control_set; -	/* No need to evaluate _OSC if the control was already granted. */ -	if ((root->osc_control_set & ctrl) == ctrl) -		return AE_OK; +	ctrl   = *mask; +	*mask |= root->osc_control_set;  	/* Need to check the available controls bits before requesting them. */ -	while (*mask) { -		status = acpi_pci_query_osc(root, root->osc_support_set, mask); +	do { +		status = acpi_pci_query_osc(root, support, mask);  		if (ACPI_FAILURE(status))  			return status;  		if (ctrl == *mask) @@ -380,7 +362,11 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r  		decode_osc_control(root, "platform does not support",  				   ctrl & ~(*mask));  		ctrl = *mask; -	} +	} while (*mask); + +	/* No need to request _OSC if the control was already granted. */ +	if ((root->osc_control_set & ctrl) == ctrl) +		return AE_OK;  	if ((ctrl & req) != req) {  		decode_osc_control(root, "not requesting control; platform does not support", @@ -399,25 +385,9 @@ static acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 r  	return AE_OK;  } -static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, -				 bool is_pcie) +static u32 calculate_support(void)  { -	u32 support, control, requested; -	acpi_status status; -	struct acpi_device *device = root->device; -	acpi_handle handle = device->handle; - -	/* -	 * Apple always return failure on _OSC calls when _OSI("Darwin") has -	 * been called successfully. We know the feature set supported by the -	 * platform, so avoid calling _OSC at all -	 */ -	if (x86_apple_machine) { -		root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL; -		decode_osc_control(root, "OS assumes control of", -				   root->osc_control_set); -		return; -	} +	u32 support;  	/*  	 * All supported architectures that use ACPI have support for @@ -434,30 +404,12 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,  	if (IS_ENABLED(CONFIG_PCIE_EDR))  		support |= OSC_PCI_EDR_SUPPORT; -	decode_osc_support(root, "OS supports", support); -	status = acpi_pci_osc_support(root, support); -	if (ACPI_FAILURE(status)) { -		*no_aspm = 1; - -		/* _OSC is optional for PCI host bridges */ -		if ((status == AE_NOT_FOUND) && !is_pcie) -			return; - -		dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", -			 acpi_format_exception(status)); -		return; -	} - -	if (pcie_ports_disabled) { -		dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); -		return; -	} +	return support; +} -	if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { -		decode_osc_support(root, "not requesting OS control; OS requires", -				   ACPI_PCIE_REQ_SUPPORT); -		return; -	} +static u32 calculate_control(void) +{ +	u32 control;  	control = OSC_PCI_EXPRESS_CAPABILITY_CONTROL  		| OSC_PCI_EXPRESS_PME_CONTROL; @@ -483,11 +435,59 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,  	if (IS_ENABLED(CONFIG_PCIE_DPC) && IS_ENABLED(CONFIG_PCIE_EDR))  		control |= OSC_PCI_EXPRESS_DPC_CONTROL; -	requested = control; -	status = acpi_pci_osc_control_set(handle, &control, -					  OSC_PCI_EXPRESS_CAPABILITY_CONTROL); +	return control; +} + +static bool os_control_query_checks(struct acpi_pci_root *root, u32 support) +{ +	struct acpi_device *device = root->device; + +	if (pcie_ports_disabled) { +		dev_info(&device->dev, "PCIe port services disabled; not requesting _OSC control\n"); +		return false; +	} + +	if ((support & ACPI_PCIE_REQ_SUPPORT) != ACPI_PCIE_REQ_SUPPORT) { +		decode_osc_support(root, "not requesting OS control; OS requires", +				   ACPI_PCIE_REQ_SUPPORT); +		return false; +	} + +	return true; +} + +static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm, +				 bool is_pcie) +{ +	u32 support, control = 0, requested = 0; +	acpi_status status; +	struct acpi_device *device = root->device; +	acpi_handle handle = device->handle; + +	/* +	 * Apple always return failure on _OSC calls when _OSI("Darwin") has +	 * been called successfully. We know the feature set supported by the +	 * platform, so avoid calling _OSC at all +	 */ +	if (x86_apple_machine) { +		root->osc_control_set = ~OSC_PCI_EXPRESS_PME_CONTROL; +		decode_osc_control(root, "OS assumes control of", +				   root->osc_control_set); +		return; +	} + +	support = calculate_support(); + +	decode_osc_support(root, "OS supports", support); + +	if (os_control_query_checks(root, support)) +		requested = control = calculate_control(); + +	status = acpi_pci_osc_control_set(handle, &control, support);  	if (ACPI_SUCCESS(status)) { -		decode_osc_control(root, "OS now controls", control); +		if (control) +			decode_osc_control(root, "OS now controls", control); +  		if (acpi_gbl_FADT.boot_flags & ACPI_FADT_NO_ASPM) {  			/*  			 * We have ASPM control, but the FADT indicates that @@ -498,11 +498,6 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,  			*no_aspm = 1;  		}  	} else { -		decode_osc_control(root, "OS requested", requested); -		decode_osc_control(root, "platform willing to grant", control); -		dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", -			acpi_format_exception(status)); -  		/*  		 * We want to disable ASPM here, but aspm_disabled  		 * needs to remain in its state from boot so that we @@ -511,6 +506,18 @@ static void negotiate_os_control(struct acpi_pci_root *root, int *no_aspm,  		 * root scan.  		 */  		*no_aspm = 1; + +		/* _OSC is optional for PCI host bridges */ +		if ((status == AE_NOT_FOUND) && !is_pcie) +			return; + +		if (control) { +			decode_osc_control(root, "OS requested", requested); +			decode_osc_control(root, "platform willing to grant", control); +		} + +		dev_info(&device->dev, "_OSC: platform retains control of PCIe features (%s)\n", +			 acpi_format_exception(status));  	}  } |