|
@@ -33,7 +33,6 @@
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pm_runtime.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci.h>
|
|
#include <linux/pci-acpi.h>
|
|
#include <linux/pci-acpi.h>
|
|
-#include <linux/pci-aspm.h>
|
|
|
|
#include <linux/acpi.h>
|
|
#include <linux/acpi.h>
|
|
#include <linux/slab.h>
|
|
#include <linux/slab.h>
|
|
#include <acpi/acpi_bus.h>
|
|
#include <acpi/acpi_bus.h>
|
|
@@ -226,22 +225,31 @@ static acpi_status acpi_pci_run_osc(acpi_handle handle,
|
|
return status;
|
|
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;
|
|
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_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);
|
|
status = acpi_pci_run_osc(root->device->handle, capbuf, &result);
|
|
if (ACPI_SUCCESS(status)) {
|
|
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;
|
|
return status;
|
|
}
|
|
}
|
|
@@ -255,7 +263,7 @@ static acpi_status acpi_pci_osc_support(struct acpi_pci_root *root, u32 flags)
|
|
if (ACPI_FAILURE(status))
|
|
if (ACPI_FAILURE(status))
|
|
return status;
|
|
return status;
|
|
mutex_lock(&osc_lock);
|
|
mutex_lock(&osc_lock);
|
|
- status = acpi_pci_query_osc(root, flags);
|
|
|
|
|
|
+ status = acpi_pci_query_osc(root, flags, NULL);
|
|
mutex_unlock(&osc_lock);
|
|
mutex_unlock(&osc_lock);
|
|
return status;
|
|
return status;
|
|
}
|
|
}
|
|
@@ -365,55 +373,70 @@ out:
|
|
EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
|
|
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;
|
|
acpi_status status;
|
|
- u32 control_req, result, capbuf[3];
|
|
|
|
|
|
+ u32 ctrl, capbuf[3];
|
|
acpi_handle tmp;
|
|
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;
|
|
return AE_TYPE;
|
|
|
|
|
|
root = acpi_pci_find_root(handle);
|
|
root = acpi_pci_find_root(handle);
|
|
if (!root)
|
|
if (!root)
|
|
return AE_NOT_EXIST;
|
|
return AE_NOT_EXIST;
|
|
|
|
|
|
|
|
+ status = acpi_get_handle(handle, "_OSC", &tmp);
|
|
|
|
+ if (ACPI_FAILURE(status))
|
|
|
|
+ return status;
|
|
|
|
+
|
|
mutex_lock(&osc_lock);
|
|
mutex_lock(&osc_lock);
|
|
|
|
+
|
|
|
|
+ *mask = ctrl | root->osc_control_set;
|
|
/* No need to evaluate _OSC if the control was already granted. */
|
|
/* 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;
|
|
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))
|
|
if (ACPI_FAILURE(status))
|
|
goto out;
|
|
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;
|
|
status = AE_SUPPORT;
|
|
goto out;
|
|
goto out;
|
|
}
|
|
}
|
|
|
|
|
|
capbuf[OSC_QUERY_TYPE] = 0;
|
|
capbuf[OSC_QUERY_TYPE] = 0;
|
|
capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
|
|
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))
|
|
if (ACPI_SUCCESS(status))
|
|
- root->osc_control_set = result;
|
|
|
|
|
|
+ root->osc_control_set = *mask;
|
|
out:
|
|
out:
|
|
mutex_unlock(&osc_lock);
|
|
mutex_unlock(&osc_lock);
|
|
return status;
|
|
return status;
|
|
@@ -544,14 +567,6 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
|
|
if (flags != base_flags)
|
|
if (flags != base_flags)
|
|
acpi_pci_osc_support(root, 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);
|
|
pci_acpi_add_bus_pm_notifier(device, root->bus);
|
|
if (device->wakeup.flags.run_wake)
|
|
if (device->wakeup.flags.run_wake)
|
|
device_set_run_wake(root->bus->bridge, true);
|
|
device_set_run_wake(root->bus->bridge, true);
|