Skip to content

Commit 75fb60f

Browse files
rjwysockijbarnes993
authored andcommitted
ACPI/PCI: Negotiate _OSC control bits before requesting them
It is possible that the BIOS will not grant control of all _OSC features requested via acpi_pci_osc_control_set(), so it is recommended to negotiate the final set of _OSC features with the query flag set before calling _OSC to request control of these features. To implement it, rework acpi_pci_osc_control_set() so that the caller can specify the mask of _OSC control bits to negotiate and the mask of _OSC control bits that are absolutely necessary to it. Then, acpi_pci_osc_control_set() will run _OSC queries in a loop until the mask of _OSC control bits returned by the BIOS is equal to the mask passed to it. Also, before running the _OSC request acpi_pci_osc_control_set() will check if the caller's required control bits are present in the final mask. Using this mechanism we will be able to avoid situations in which the BIOS doesn't grant control of certain _OSC features, because they depend on some other _OSC features that have not been requested. Signed-off-by: Rafael J. Wysocki <rjw@sisk.pl> Signed-off-by: Jesse Barnes <jbarnes@virtuousgeek.org>
1 parent 2b8fd91 commit 75fb60f

File tree

5 files changed

+49
-30
lines changed

5 files changed

+49
-30
lines changed

drivers/acpi/pci_root.c

Lines changed: 38 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -374,21 +374,32 @@ struct pci_dev *acpi_get_pci_dev(acpi_handle handle)
374374
EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
375375

376376
/**
377-
* acpi_pci_osc_control_set - commit requested control to Firmware
378-
* @handle: acpi_handle for the target ACPI object
379-
* @flags: driver's requested control bits
377+
* acpi_pci_osc_control_set - Request control of PCI root _OSC features.
378+
* @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
379+
* @mask: Mask of _OSC bits to request control of, place to store control mask.
380+
* @req: Mask of _OSC bits the control of is essential to the caller.
380381
*
381-
* Attempt to take control from Firmware on requested control bits.
382+
* Run _OSC query for @mask and if that is successful, compare the returned
383+
* mask of control bits with @req. If all of the @req bits are set in the
384+
* returned mask, run _OSC request for it.
385+
*
386+
* The variable at the @mask address may be modified regardless of whether or
387+
* not the function returns success. On success it will contain the mask of
388+
* _OSC bits the BIOS has granted control of, but its contents are meaningless
389+
* on failure.
382390
**/
383-
acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
391+
acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
384392
{
393+
struct acpi_pci_root *root;
385394
acpi_status status;
386-
u32 control_req, result, capbuf[3];
395+
u32 ctrl, capbuf[3];
387396
acpi_handle tmp;
388-
struct acpi_pci_root *root;
389397

390-
control_req = (flags & OSC_PCI_CONTROL_MASKS);
391-
if (!control_req)
398+
if (!mask)
399+
return AE_BAD_PARAMETER;
400+
401+
ctrl = *mask & OSC_PCI_CONTROL_MASKS;
402+
if ((ctrl & req) != req)
392403
return AE_TYPE;
393404

394405
root = acpi_pci_find_root(handle);
@@ -400,27 +411,33 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
400411
return status;
401412

402413
mutex_lock(&osc_lock);
414+
415+
*mask = ctrl | root->osc_control_set;
403416
/* No need to evaluate _OSC if the control was already granted. */
404-
if ((root->osc_control_set & control_req) == control_req)
417+
if ((root->osc_control_set & ctrl) == ctrl)
405418
goto out;
406419

407-
/* Need to query controls first before requesting them */
408-
flags = control_req;
409-
status = acpi_pci_query_osc(root, root->osc_support_set, &flags);
410-
if (ACPI_FAILURE(status))
411-
goto out;
420+
/* Need to check the available controls bits before requesting them. */
421+
while (*mask) {
422+
status = acpi_pci_query_osc(root, root->osc_support_set, mask);
423+
if (ACPI_FAILURE(status))
424+
goto out;
425+
if (ctrl == *mask)
426+
break;
427+
ctrl = *mask;
428+
}
412429

413-
if (flags != control_req) {
430+
if ((ctrl & req) != req) {
414431
status = AE_SUPPORT;
415432
goto out;
416433
}
417434

418435
capbuf[OSC_QUERY_TYPE] = 0;
419436
capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
420-
capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req;
421-
status = acpi_pci_run_osc(handle, capbuf, &result);
437+
capbuf[OSC_CONTROL_TYPE] = ctrl;
438+
status = acpi_pci_run_osc(handle, capbuf, mask);
422439
if (ACPI_SUCCESS(status))
423-
root->osc_control_set = result;
440+
root->osc_control_set = *mask;
424441
out:
425442
mutex_unlock(&osc_lock);
426443
return status;
@@ -551,8 +568,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
551568
if (flags != base_flags)
552569
acpi_pci_osc_support(root, flags);
553570

554-
status = acpi_pci_osc_control_set(root->device->handle,
555-
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
571+
flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
572+
status = acpi_pci_osc_control_set(root->device->handle, &flags, flags);
556573

557574
if (ACPI_FAILURE(status)) {
558575
printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");

drivers/pci/hotplug/acpi_pcihp.c

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -360,7 +360,7 @@ int acpi_get_hp_hw_control_from_firmware(struct pci_dev *pdev, u32 flags)
360360
acpi_get_name(handle, ACPI_FULL_PATHNAME, &string);
361361
dbg("Trying to get hotplug control for %s\n",
362362
(char *)string.pointer);
363-
status = acpi_pci_osc_control_set(handle, flags);
363+
status = acpi_pci_osc_control_set(handle, &flags, flags);
364364
if (ACPI_SUCCESS(status))
365365
goto got_one;
366366
if (status == AE_SUPPORT)

drivers/pci/pcie/aer/aerdrv_acpi.c

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -39,9 +39,9 @@ int aer_osc_setup(struct pcie_device *pciedev)
3939

4040
handle = acpi_find_root_bridge_handle(pdev);
4141
if (handle) {
42-
status = acpi_pci_osc_control_set(handle,
43-
OSC_PCI_EXPRESS_AER_CONTROL |
44-
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
42+
u32 flags = OSC_PCI_EXPRESS_AER_CONTROL |
43+
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
44+
status = acpi_pci_osc_control_set(handle, &flags, flags);
4545
}
4646

4747
if (ACPI_FAILURE(status)) {

drivers/pci/pcie/pme/pcie_pme_acpi.c

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -28,6 +28,7 @@ int pcie_pme_acpi_setup(struct pcie_device *srv)
2828
acpi_status status = AE_NOT_FOUND;
2929
struct pci_dev *port = srv->port;
3030
acpi_handle handle;
31+
u32 flags;
3132
int error = 0;
3233

3334
if (acpi_pci_disabled)
@@ -39,9 +40,10 @@ int pcie_pme_acpi_setup(struct pcie_device *srv)
3940
if (!handle)
4041
return -EINVAL;
4142

42-
status = acpi_pci_osc_control_set(handle,
43-
OSC_PCI_EXPRESS_PME_CONTROL |
44-
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL);
43+
flags = OSC_PCI_EXPRESS_PME_CONTROL |
44+
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
45+
46+
status = acpi_pci_osc_control_set(handle, &flags, flags);
4547
if (ACPI_FAILURE(status)) {
4648
dev_info(&port->dev,
4749
"Failed to receive control of PCIe PME service: %s\n",

include/linux/acpi.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -304,8 +304,8 @@ acpi_status acpi_run_osc(acpi_handle handle, struct acpi_osc_context *context);
304304
OSC_PCI_EXPRESS_PME_CONTROL | \
305305
OSC_PCI_EXPRESS_AER_CONTROL | \
306306
OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL)
307-
308-
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags);
307+
extern acpi_status acpi_pci_osc_control_set(acpi_handle handle,
308+
u32 *mask, u32 req);
309309
extern void acpi_early_init(void);
310310

311311
#else /* !CONFIG_ACPI */

0 commit comments

Comments
 (0)