===================================================================
@@ -225,22 +225,35 @@ static acpi_status acpi_pci_run_osc(acpi
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;
+ } else {
+ root->osc_control_qry = result;
+ root->osc_queried = 1;
+ }
}
return status;
}
@@ -254,7 +267,7 @@ static acpi_status acpi_pci_osc_support(
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;
}
@@ -363,6 +376,48 @@ out:
}
EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
+ /**
+ * acpi_pci_osc_control_query - Get the _OSC bits the kernel can control.
+ * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
+ * @mask: Mask of _OSC bits to query and the place to put the result into.
+ **/
+acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask)
+{
+ struct acpi_pci_root *root;
+ acpi_handle tmp;
+ acpi_status status = AE_OK;
+ u32 ctrl = *mask;
+
+ if (!(ctrl & OSC_PCI_CONTROL_MASKS))
+ return AE_BAD_PARAMETER;
+
+ 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 |= root->osc_control_set;
+ if ((ctrl & root->osc_control_set) == ctrl)
+ goto out;
+
+ for (ctrl = 0; *mask != ctrl; ctrl = *mask) {
+ status = acpi_pci_query_osc(root, root->osc_support_set, mask);
+ if (ACPI_FAILURE(status))
+ break;
+ }
+
+ out:
+ mutex_unlock(&osc_lock);
+
+ return status;
+}
+EXPORT_SYMBOL(acpi_pci_osc_control_query);
+
/**
* acpi_pci_osc_control_set - commit requested control to Firmware
* @handle: acpi_handle for the target ACPI object
@@ -396,7 +451,7 @@ acpi_status acpi_pci_osc_control_set(acp
/* Need to query controls first before requesting them */
if (!root->osc_queried) {
- status = acpi_pci_query_osc(root, root->osc_support_set);
+ status = acpi_pci_query_osc(root, root->osc_support_set, NULL);
if (ACPI_FAILURE(status))
goto out;
}
===================================================================
@@ -305,6 +305,7 @@ acpi_status acpi_run_osc(acpi_handle han
OSC_PCI_EXPRESS_AER_CONTROL | \
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
+extern acpi_status acpi_pci_osc_control_query(acpi_handle handle, u32 *mask);
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
extern void acpi_early_init(void);