|
@@ -374,21 +374,32 @@ 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.
|
|
|
*
|
|
|
- * Attempt to take control from Firmware on requested control bits.
|
|
|
+ * 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.
|
|
|
+ *
|
|
|
+ * 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;
|
|
|
|
|
|
- control_req = (flags & OSC_PCI_CONTROL_MASKS);
|
|
|
- if (!control_req)
|
|
|
+ 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);
|
|
@@ -400,27 +411,33 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
|
|
|
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 */
|
|
|
- flags = control_req;
|
|
|
- status = acpi_pci_query_osc(root, root->osc_support_set, &flags);
|
|
|
- if (ACPI_FAILURE(status))
|
|
|
- goto out;
|
|
|
+ /* 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 (flags != control_req) {
|
|
|
+ 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;
|
|
@@ -551,8 +568,8 @@ 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);
|
|
|
+ flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
|
|
|
+ status = acpi_pci_osc_control_set(root->device->handle, &flags, flags);
|
|
|
|
|
|
if (ACPI_FAILURE(status)) {
|
|
|
printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");
|