aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/acpi
diff options
context:
space:
mode:
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");