aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci
diff options
context:
space:
mode:
authorAaron Lu <aaron.lu@intel.com>2015-03-25 02:37:06 -0400
committerBjorn Helgaas <bhelgaas@google.com>2015-04-08 17:25:25 -0400
commite33caa82e221b0bbeba373b507e3f134dc2efa1a (patch)
tree5a5b5cb497a21c0342ac0a7d2956b366020fef68 /drivers/pci
parent3390e0850b711d163b35508464cfbe0a4477dfe2 (diff)
PCI/ACPI: Optimize device state transition delays
The PCI "ACPI additions for FW latency optimizations" ECN (link below) defines two functions in the PCI _DSM: Function 8, "Reset Delay," applies to the entire hierarchy below a PCI host bridge. If it returns one, the OS may assume that all devices in the hierarchy have already completed power-on reset delays. Function 9, "Device Readiness Durations," applies only to the object where it is located. It returns delay durations required after various events if the device requires less time than the spec requires. Delays from this function take precedence over the Reset Delay function. Add support for Reset Delay and part of Device Readiness Durations. [bhelgaas: changelog, comments] Link: https://www.pcisig.com/specifications/conventional/pci_firmware/ECN_fw_latency_optimization_final.pdf Signed-off-by: Aaron Lu <aaron.lu@intel.com> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com>
Diffstat (limited to 'drivers/pci')
-rw-r--r--drivers/pci/pci-acpi.c74
1 files changed, 74 insertions, 0 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index bea6be4992c3..5eba74716900 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -537,11 +537,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
537 537
538void acpi_pci_add_bus(struct pci_bus *bus) 538void acpi_pci_add_bus(struct pci_bus *bus)
539{ 539{
540 union acpi_object *obj;
541 struct pci_host_bridge *bridge;
542
540 if (acpi_pci_disabled || !bus->bridge) 543 if (acpi_pci_disabled || !bus->bridge)
541 return; 544 return;
542 545
543 acpi_pci_slot_enumerate(bus); 546 acpi_pci_slot_enumerate(bus);
544 acpiphp_enumerate_slots(bus); 547 acpiphp_enumerate_slots(bus);
548
549 /*
550 * For a host bridge, check its _DSM for function 8 and if
551 * that is available, mark it in pci_host_bridge.
552 */
553 if (!pci_is_root_bus(bus))
554 return;
555
556 obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), pci_acpi_dsm_uuid, 3,
557 RESET_DELAY_DSM, NULL);
558 if (!obj)
559 return;
560
561 if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
562 bridge = pci_find_host_bridge(bus);
563 bridge->ignore_reset_delay = 1;
564 }
565 ACPI_FREE(obj);
545} 566}
546 567
547void acpi_pci_remove_bus(struct pci_bus *bus) 568void acpi_pci_remove_bus(struct pci_bus *bus)
@@ -567,6 +588,57 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
567 check_children); 588 check_children);
568} 589}
569 590
591/**
592 * pci_acpi_optimize_delay - optimize PCI D3 and D3cold delay from ACPI
593 * @pdev: the PCI device whose delay is to be updated
594 * @adev: the companion ACPI device of this PCI device
595 *
596 * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM
597 * control method of either the device itself or the PCI host bridge.
598 *
599 * Function 8, "Reset Delay," applies to the entire hierarchy below a PCI
600 * host bridge. If it returns one, the OS may assume that all devices in
601 * the hierarchy have already completed power-on reset delays.
602 *
603 * Function 9, "Device Readiness Durations," applies only to the object
604 * where it is located. It returns delay durations required after various
605 * events if the device requires less time than the spec requires. Delays
606 * from this function take precedence over the Reset Delay function.
607 *
608 * These _DSM functions are defined by the draft ECN of January 28, 2014,
609 * titled "ACPI additions for FW latency optimizations."
610 */
611static void pci_acpi_optimize_delay(struct pci_dev *pdev,
612 acpi_handle handle)
613{
614 struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
615 int value;
616 union acpi_object *obj, *elements;
617
618 if (bridge->ignore_reset_delay)
619 pdev->d3cold_delay = 0;
620
621 obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3,
622 FUNCTION_DELAY_DSM, NULL);
623 if (!obj)
624 return;
625
626 if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) {
627 elements = obj->package.elements;
628 if (elements[0].type == ACPI_TYPE_INTEGER) {
629 value = (int)elements[0].integer.value / 1000;
630 if (value < PCI_PM_D3COLD_WAIT)
631 pdev->d3cold_delay = value;
632 }
633 if (elements[3].type == ACPI_TYPE_INTEGER) {
634 value = (int)elements[3].integer.value / 1000;
635 if (value < PCI_PM_D3_WAIT)
636 pdev->d3_delay = value;
637 }
638 }
639 ACPI_FREE(obj);
640}
641
570static void pci_acpi_setup(struct device *dev) 642static void pci_acpi_setup(struct device *dev)
571{ 643{
572 struct pci_dev *pci_dev = to_pci_dev(dev); 644 struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -575,6 +647,8 @@ static void pci_acpi_setup(struct device *dev)
575 if (!adev) 647 if (!adev)
576 return; 648 return;
577 649
650 pci_acpi_optimize_delay(pci_dev, adev->handle);
651
578 pci_acpi_add_pm_notifier(adev, pci_dev); 652 pci_acpi_add_pm_notifier(adev, pci_dev);
579 if (!adev->wakeup.flags.valid) 653 if (!adev->wakeup.flags.valid)
580 return; 654 return;