summaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--drivers/acpi/pci_root.c59
-rw-r--r--drivers/pci/hotplug/acpi_pcihp.c2
-rw-r--r--drivers/pci/pcie/aer/aerdrv_acpi.c6
-rw-r--r--drivers/pci/pcie/pme/pcie_pme_acpi.c8
-rw-r--r--include/linux/acpi.h4
5 files changed, 49 insertions, 30 deletions
diff --git a/drivers/acpi/pci_root.c b/drivers/acpi/pci_root.c
index 77cd19697b1e..c34713112520 100644
--- a/drivers/acpi/pci_root.c
+++ b/drivers/acpi/pci_root.c
@@ -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");
diff --git a/drivers/pci/hotplug/acpi_pcihp.c b/drivers/pci/hotplug/acpi_pcihp.c
index 45fcc1e96df9..3d93d529a7bd 100644
--- a/drivers/pci/hotplug/acpi_pcihp.c
+++ b/drivers/pci/hotplug/acpi_pcihp.c
@@ -360,7 +360,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
dbg("Trying to get hotplug control for %s\n",
(char *)string.pointer);
- status = acpi_pci_osc_control_set(handle, flags);
+ status = acpi_pci_osc_control_set(handle, &flags, flags);
if (ACPI_SUCCESS(status))
goto got_one;
if (status == AE_SUPPORT)
diff --git a/drivers/pci/pcie/aer/aerdrv_acpi.c b/drivers/pci/pcie/aer/aerdrv_acpi.c
index f278d7b0d95d..3a276a0cea93 100644
--- a/drivers/pci/pcie/aer/aerdrv_acpi.c
+++ b/drivers/pci/pcie/aer/aerdrv_acpi.c
@@ -39,9 +39,9 @@ int aer_osc_setup(struct pcie_device *pciedev)
handle = acpi_find_root_bridge_handle(pdev);
if (handle) {
- status = acpi_pci_osc_control_set(handle,
- OSC_PCI_EXPRESS_AER_CONTROL |
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ u32 flags = OSC_PCI_EXPRESS_AER_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
+ status = acpi_pci_osc_control_set(handle, &flags, flags);
}
if (ACPI_FAILURE(status)) {
diff --git a/drivers/pci/pcie/pme/pcie_pme_acpi.c b/drivers/pci/pcie/pme/pcie_pme_acpi.c
index 83ab2287ae3f..be20222b12d3 100644
--- a/drivers/pci/pcie/pme/pcie_pme_acpi.c
+++ b/drivers/pci/pcie/pme/pcie_pme_acpi.c
@@ -28,6 +28,7 @@ int pcie_pme_acpi_setup(struct pcie_device *srv)
acpi_status status = AE_NOT_FOUND;
struct pci_dev *port = srv->port;
acpi_handle handle;
+ u32 flags;
int error = 0;
if (acpi_pci_disabled)
@@ -39,9 +40,10 @@ int pcie_pme_acpi_setup(struct pcie_device *srv)
if (!handle)
return -EINVAL;
- status = acpi_pci_osc_control_set(handle,
- OSC_PCI_EXPRESS_PME_CONTROL |
- OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
+ flags = OSC_PCI_EXPRESS_PME_CONTROL |
+ OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
+
+ status = acpi_pci_osc_control_set(handle, &flags, flags);
if (ACPI_FAILURE(status)) {
dev_info(&port->dev,
"Failed to receive control of PCIe PME service: %s\n",
diff --git a/include/linux/acpi.h b/include/linux/acpi.h
index ccf94dc5acdf..c227757feb06 100644
--- a/include/linux/acpi.h
+++ b/include/linux/acpi.h
@@ -304,8 +304,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
OSC_PCI_EXPRESS_PME_CONTROL | \
OSC_PCI_EXPRESS_AER_CONTROL | \
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
-
-extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
+extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
+ u32 *mask, u32 req);
extern void acpi_early_init(void);
#else /* !CONFIG_ACPI */