From patchwork Mon Mar 23 09:17:44 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Aaron Lu X-Patchwork-Id: 6071241 X-Patchwork-Delegate: bhelgaas@google.com Return-Path: X-Original-To: patchwork-linux-pci@patchwork.kernel.org Delivered-To: patchwork-parsemail@patchwork1.web.kernel.org Received: from mail.kernel.org (mail.kernel.org [198.145.29.136]) by patchwork1.web.kernel.org (Postfix) with ESMTP id 716979F2A9 for ; Mon, 23 Mar 2015 09:19:22 +0000 (UTC) Received: from mail.kernel.org (localhost [127.0.0.1]) by mail.kernel.org (Postfix) with ESMTP id 7B7B020166 for ; Mon, 23 Mar 2015 09:19:21 +0000 (UTC) Received: from vger.kernel.org (vger.kernel.org [209.132.180.67]) by mail.kernel.org (Postfix) with ESMTP id B6B9520253 for ; Mon, 23 Mar 2015 09:19:19 +0000 (UTC) Received: (majordomo@vger.kernel.org) by vger.kernel.org via listexpand id S1752071AbbCWJTR (ORCPT ); Mon, 23 Mar 2015 05:19:17 -0400 Received: from mga03.intel.com ([134.134.136.65]:2783 "EHLO mga03.intel.com" rhost-flags-OK-OK-OK-OK) by vger.kernel.org with ESMTP id S1751935AbbCWJTQ (ORCPT ); Mon, 23 Mar 2015 05:19:16 -0400 Received: from fmsmga003.fm.intel.com ([10.253.24.29]) by orsmga103.jf.intel.com with ESMTP; 23 Mar 2015 02:19:17 -0700 X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="5.11,451,1422950400"; d="scan'208";a="471175320" Received: from aaronlu.sh.intel.com ([10.239.159.58]) by FMSMGA003.fm.intel.com with ESMTP; 23 Mar 2015 02:19:15 -0700 Message-ID: <550FDA38.2090505@intel.com> Date: Mon, 23 Mar 2015 17:17:44 +0800 From: Aaron Lu MIME-Version: 1.0 To: Bjorn Helgaas CC: "Rafael J. Wysocki" , ACPI Devel Mailing List , Linux PCI Subject: [PATCH 2/2] PCI / ACPI: PCI delay optimization from ACPI References: <54FD4FB9.2060802@intel.com> <5222588.FaRe37n2T1@vostro.rjw.lan> <54FE93A4.9040908@intel.com> <20150320210354.GK26935@google.com> In-Reply-To: <20150320210354.GK26935@google.com> Sender: linux-pci-owner@vger.kernel.org Precedence: bulk List-ID: X-Mailing-List: linux-pci@vger.kernel.org X-Spam-Status: No, score=-6.9 required=5.0 tests=BAYES_00, RCVD_IN_DNSWL_HI, T_RP_MATCHES_RCVD, UNPARSEABLE_RELAY autolearn=unavailable version=3.3.1 X-Spam-Checker-Version: SpamAssassin 3.3.1 (2010-03-16) on mail.kernel.org X-Virus-Scanned: ClamAV using ClamSMTP An ECN meant to specify possible delay optimizations is available on the PCI website: https://www.pcisig.com/specifications/conventional/pci_firmware/ECN_fw_latency_optimization_final.pdf where it has defined two functions for an UUID specified _DSM: Function 8: If system firmware assumes the responsibility of post Conventional Reset delay (and informs the Operating System via this DSM function) on Sx Resume (such as boot from ACPI S5, or resume from ACPI S4 or S3 states), the Operating System may assume sufficient time has elapsed since the end of reset, and devices within the PCI subsystem are ready for Configuration Access. If the system firmware supports runtime power gating on any of the device within PCI subsystem covered by this DSM function, the system firmware is responsible for covering the necessary post power-on reset delay. Function 9: Specify various smaller delay values than required by the SPEC for individual PCI devices like shorter delay values after conventional reset, D3hot to D0 transition, functional level reset, etc. This patche adds support for function 8 and part of function 9. For function 8, the patch will check if the required _DSM function satisfies the requirement and then set the per PCI device's d3cold_delay variable to zero. For function 9, the values affecting delays after conventional reset and D3hot->D0 are examined and the per PCI device's d3cold_delay and d3_delay are updated if the _DSM's return value is smaller than what the SPEC requires. Signed-off-by: Aaron Lu --- drivers/pci/pci-acpi.c | 63 ++++++++++++++++++++++++++++++++++++++++++++++++++ drivers/pci/pci.h | 2 ++ 2 files changed, 65 insertions(+) diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c index 6ef2019073e2..2ebd02d814d7 100644 --- a/drivers/pci/pci-acpi.c +++ b/drivers/pci/pci-acpi.c @@ -563,6 +563,66 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev) check_children); } +/** + * pci_acpi_delay_optimize - optimize PCI D3 and D3cold delay from ACPI + * @pdev: the PCI device whose delay is to be updated + * @adev: the companion ACPI device of this PCI device + * + * Update the d3_delay and d3cold_delay of a PCI device from the ACPI _DSM + * control method of either its own or its parent bridge. + * + * The UUID of the _DSM control method, together with other information like + * which delay values can be optimized, etc. is defined in a ECN available on + * PCIsig.com titled as: ACPI additions for FW latency optimizations. + * Function 9 of the ACPI _DSM control method, if available for a specific PCI + * device, provides various possible delay values that are less than what the + * SPEC requires. Here, we only deal with d3_delay and d3cold_delay. Others + * can be added later. + * Function 8 of the ACPI _DSM control method, if available for the PCI host + * bridge, means all its children devices do not need the reset delay when + * leaving from D3cold state. + */ +static void pci_acpi_delay_optimize(struct pci_dev *pdev, + struct acpi_device *adev) +{ + acpi_handle handle = adev->handle; + int value; + union acpi_object *obj, *elements; + + obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3, + FUNCTION_DELAY_DSM, NULL); + if (obj) { + if (obj->type == ACPI_TYPE_PACKAGE && obj->package.count == 5) { + elements = obj->package.elements; + if (elements[0].type == ACPI_TYPE_INTEGER) { + value = (int)elements[0].integer.value / 1000; + if (value < PCI_PM_D3COLD_WAIT) + pdev->d3cold_delay = value; + } + if (elements[3].type == ACPI_TYPE_INTEGER) { + value = (int)elements[3].integer.value / 1000; + if (value < PCI_PM_D3_WAIT) + pdev->d3_delay = value; + } + } + kfree(obj); + } + + /* Function 8 is only applicable to host bridge */ + if (pdev->bus->bridge->parent) + return; + + handle = ACPI_HANDLE(pdev->bus->bridge); + obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3, + RESET_DELAY_DSM, NULL); + if (!obj) + return; + + if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) + pdev->d3cold_delay = 0; + kfree(obj); +} + static void pci_acpi_setup(struct device *dev) { struct pci_dev *pci_dev = to_pci_dev(dev); @@ -571,6 +631,9 @@ static void pci_acpi_setup(struct device *dev) if (!adev) return; + if (pci_dev->pm_cap) + pci_acpi_delay_optimize(pci_dev, adev); + pci_acpi_add_pm_notifier(adev, pci_dev); if (!adev->wakeup.flags.valid) return; diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h index c901ab84cf3b..3eaefac5acc5 100644 --- a/drivers/pci/pci.h +++ b/drivers/pci/pci.h @@ -325,6 +325,8 @@ static inline int pci_dev_specific_reset(struct pci_dev *dev, int probe) extern const u8 pci_acpi_dsm_uuid[]; #define DEVICE_LABEL_DSM 0x07 +#define RESET_DELAY_DSM 0x08 +#define FUNCTION_DELAY_DSM 0x09 #endif #endif /* DRIVERS_PCI_H */