aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
authorRafael J. Wysocki <rjw@sisk.pl>2010-08-23 17:53:11 -0400
committerJesse Barnes <jbarnes@virtuousgeek.org>2010-08-24 16:44:40 -0400
commit75fb60f26befb59dbfa05cb122972642b7bdd219 (patch)
treebe015dd00e7748e45f3691f04a16c204546b3026 /drivers/acpi
parent2b8fd9186d9275b07aef43e5bb4e98cd571f9a7d (diff)
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>
Diffstat (limited to 'drivers/acpi')
-rw-r--r--drivers/acpi/pci_root.c59
1 files changed, 38 insertions, 21 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:
374EXPORT_SYMBOL_GPL(acpi_get_pci_dev); 374EXPORT_SYMBOL_GPL(acpi_get_pci_dev);
375 375
376/** 376/**
377 * acpi_pci_osc_control_set - commit requested control to Firmware 377 * acpi_pci_osc_control_set - Request control of PCI root _OSC features.
378 * @handle: acpi_handle for the target ACPI object 378 * @handle: ACPI handle of a PCI root bridge (or PCIe Root Complex).
379 * @flags: driver's requested control bits 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.
380 * 381 *
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.
382 **/ 390 **/
383acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags) 391acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 *mask, u32 req)
384{ 392{
393 struct acpi_pci_root *root;
385 acpi_status status; 394 acpi_status status;
386 u32 control_req, result, capbuf[3]; 395 u32 ctrl, capbuf[3];
387 acpi_handle tmp; 396 acpi_handle tmp;
388 struct acpi_pci_root *root;
389 397
390 control_req = (flags & OSC_PCI_CONTROL_MASKS); 398 if (!mask)
391 if (!control_req) 399 return AE_BAD_PARAMETER;
400
401 ctrl = *mask & OSC_PCI_CONTROL_MASKS;
402 if ((ctrl & req) != req)
392 return AE_TYPE; 403 return AE_TYPE;
393 404
394 root = acpi_pci_find_root(handle); 405 root = acpi_pci_find_root(handle);
@@ -400,27 +411,33 @@ acpi_status acpi_pci_osc_control_set(acpi_handle handle, u32 flags)
400 return status; 411 return status;
401 412
402 mutex_lock(&osc_lock); 413 mutex_lock(&osc_lock);
414
415 *mask = ctrl | root->osc_control_set;
403 /* No need to evaluate _OSC if the control was already granted. */ 416 /* 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)
405 goto out; 418 goto out;
406 419
407 /* Need to query controls first before requesting them */ 420 /* Need to check the available controls bits before requesting them. */
408 flags = control_req; 421 while (*mask) {
409 status = acpi_pci_query_osc(root, root->osc_support_set, &flags); 422 status = acpi_pci_query_osc(root, root->osc_support_set, mask);
410 if (ACPI_FAILURE(status)) 423 if (ACPI_FAILURE(status))
411 goto out; 424 goto out;
425 if (ctrl == *mask)
426 break;
427 ctrl = *mask;
428 }
412 429
413 if (flags != control_req) { 430 if ((ctrl & req) != req) {
414 status = AE_SUPPORT; 431 status = AE_SUPPORT;
415 goto out; 432 goto out;
416 } 433 }
417 434
418 capbuf[OSC_QUERY_TYPE] = 0; 435 capbuf[OSC_QUERY_TYPE] = 0;
419 capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set; 436 capbuf[OSC_SUPPORT_TYPE] = root->osc_support_set;
420 capbuf[OSC_CONTROL_TYPE] = root->osc_control_set | control_req; 437 capbuf[OSC_CONTROL_TYPE] = ctrl;
421 status = acpi_pci_run_osc(handle, capbuf, &result); 438 status = acpi_pci_run_osc(handle, capbuf, mask);
422 if (ACPI_SUCCESS(status)) 439 if (ACPI_SUCCESS(status))
423 root->osc_control_set = result; 440 root->osc_control_set = *mask;
424out: 441out:
425 mutex_unlock(&osc_lock); 442 mutex_unlock(&osc_lock);
426 return status; 443 return status;
@@ -551,8 +568,8 @@ static int __devinit acpi_pci_root_add(struct acpi_device *device)
551 if (flags != base_flags) 568 if (flags != base_flags)
552 acpi_pci_osc_support(root, flags); 569 acpi_pci_osc_support(root, flags);
553 570
554 status = acpi_pci_osc_control_set(root->device->handle, 571 flags = OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL;
555 OSC_PCI_EXPRESS_CAP_STRUCTURE_CONTROL); 572 status = acpi_pci_osc_control_set(root->device->handle, &flags, flags);
556 573
557 if (ACPI_FAILURE(status)) { 574 if (ACPI_FAILURE(status)) {
558 printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n"); 575 printk(KERN_INFO "Unable to assume PCIe control: Disabling ASPM\n");