diff options
Diffstat (limited to 'drivers/acpi')
-rw-r--r-- | drivers/acpi/pci_root.c | 59 |
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: | |||
374 | EXPORT_SYMBOL_GPL(acpi_get_pci_dev); | 374 | EXPORT_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 | **/ |
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) |
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; |
424 | out: | 441 | out: |
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"); |