summaryrefslogtreecommitdiffstats
path: root/drivers/pci/pci-acpi.c
diff options
context:
space:
mode:
authorLinus Torvalds <torvalds@linux-foundation.org>2015-04-13 15:45:47 -0700
committerLinus Torvalds <torvalds@linux-foundation.org>2015-04-13 15:45:47 -0700
commit3be1b98e073bdd4c1bb3144201a927c4a21330ba (patch)
tree6eb0619a4715d8f83388e8fd7a56f58d1c99f6cf /drivers/pci/pci-acpi.c
parent392b46f31f43a71c5391eb9cffe304979d2d6c30 (diff)
parent5468d5a64bf1e002e5081fa280186d0eba09fa0e (diff)
downloadlinux-3be1b98e073bdd4c1bb3144201a927c4a21330ba.tar.bz2
Merge tag 'pci-v4.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci
Pull PCI changes from Bjorn Helgaas: "Enumeration - Read capability list as dwords, not bytes (Sean O. Stalley) Resource management - Don't check for PNP overlaps with unassigned PCI BARs (Bjorn Helgaas) - Mark invalid BARs as unassigned (Bjorn Helgaas) - Show driver, BAR#, and resource on pci_ioremap_bar() failure (Bjorn Helgaas) - Fail pci_ioremap_bar() on unassigned resources (Bjorn Helgaas) - Assign resources before drivers claim devices (Yijing Wang) - Claim bus resources before pci_bus_add_devices() (Yijing Wang) Power management - Optimize device state transition delays (Aaron Lu) - Don't clear ASPM bits when the FADT declares it's unsupported (Matthew Garrett) Virtualization - Add ACS quirks for Intel 1G NICs (Alex Williamson) IOMMU - Add ptr to OF node arg to of_iommu_configure() (Murali Karicheri) - Move of_dma_configure() to device.c to help re-use (Murali Karicheri) - Fix size when dma-range is not used (Murali Karicheri) - Add helper functions pci_get[put]_host_bridge_device() (Murali Karicheri) - Add of_pci_dma_configure() to update DMA configuration (Murali Karicheri) - Update DMA configuration from DT (Murali Karicheri) - dma-mapping: limit IOMMU mapping size (Murali Karicheri) - Calculate device DMA masks based on DT dma-range size (Murali Karicheri) ARM Versatile host bridge driver - Check for devm_ioremap_resource() failures (Jisheng Zhang) Broadcom iProc host bridge driver - Add Broadcom iProc PCIe driver (Ray Jui) Marvell MVEBU host bridge driver - Add suspend/resume support (Thomas Petazzoni) Renesas R-Car host bridge driver - Fix position of MSI enable bit (Nobuhiro Iwamatsu) - Write zeroes to reserved PCIEPARL bits (Nobuhiro Iwamatsu) - Change PCIEPARL and PCIEPARH to PCIEPALR and PCIEPAUR (Nobuhiro Iwamatsu) - Verify that mem_res is 64K-aligned (Nobuhiro Iwamatsu) Samsung Exynos host bridge driver - Fix INTx enablement statement termination error (Jaehoon Chung) Miscellaneous - Make a shareable UUID for PCI firmware ACPI _DSM (Aaron Lu) - Clarify policy for vendor IDs in pci.txt (Michael S. Tsirkin)" * tag 'pci-v4.1-changes' of git://git.kernel.org/pub/scm/linux/kernel/git/helgaas/pci: (36 commits) PCI: Read capability list as dwords, not bytes PCI: layerscape: Simplify platform_get_resource_byname() failure checking PCI: keystone: Don't dereference possible NULL pointer PCI: versatile: Check for devm_ioremap_resource() failures PCI: Don't clear ASPM bits when the FADT declares it's unsupported PCI: Clarify policy for vendor IDs in pci.txt PCI/ACPI: Optimize device state transition delays PCI: Export pci_find_host_bridge() for use inside PCI core PCI: Make a shareable UUID for PCI firmware ACPI _DSM PCI: Fix typo in Thunderbolt kernel message PCI: exynos: Fix INTx enablement statement termination error PCI: iproc: Add Broadcom iProc PCIe support PCI: iproc: Add DT docs for Broadcom iProc PCIe driver PCI: Export symbols required for loadable host driver modules PCI: Add ACS quirks for Intel 1G NICs PCI: mvebu: Add suspend/resume support PCI: Cleanup control flow sparc/PCI: Claim bus resources before pci_bus_add_devices() PCI: Assign resources before drivers claim devices (pci_scan_root_bus()) PCI: Fail pci_ioremap_bar() on unassigned resources ...
Diffstat (limited to 'drivers/pci/pci-acpi.c')
-rw-r--r--drivers/pci/pci-acpi.c83
1 files changed, 83 insertions, 0 deletions
diff --git a/drivers/pci/pci-acpi.c b/drivers/pci/pci-acpi.c
index c93fbe76d281..6f6f175f51f7 100644
--- a/drivers/pci/pci-acpi.c
+++ b/drivers/pci/pci-acpi.c
@@ -18,6 +18,15 @@
#include <linux/pm_qos.h>
#include "pci.h"
+/*
+ * The UUID is defined in the PCI Firmware Specification available here:
+ * https://www.pcisig.com/members/downloads/pcifw_r3_1_13Dec10.pdf
+ */
+const u8 pci_acpi_dsm_uuid[] = {
+ 0xd0, 0x37, 0xc9, 0xe5, 0x53, 0x35, 0x7a, 0x4d,
+ 0x91, 0x17, 0xea, 0x4d, 0x19, 0xc3, 0x43, 0x4d
+};
+
phys_addr_t acpi_pci_root_get_mcfg_addr(acpi_handle handle)
{
acpi_status status = AE_NOT_EXIST;
@@ -531,11 +540,32 @@ static struct pci_platform_pm_ops acpi_pci_platform_pm = {
void acpi_pci_add_bus(struct pci_bus *bus)
{
+ union acpi_object *obj;
+ struct pci_host_bridge *bridge;
+
if (acpi_pci_disabled || !bus->bridge)
return;
acpi_pci_slot_enumerate(bus);
acpiphp_enumerate_slots(bus);
+
+ /*
+ * For a host bridge, check its _DSM for function 8 and if
+ * that is available, mark it in pci_host_bridge.
+ */
+ if (!pci_is_root_bus(bus))
+ return;
+
+ obj = acpi_evaluate_dsm(ACPI_HANDLE(bus->bridge), pci_acpi_dsm_uuid, 3,
+ RESET_DELAY_DSM, NULL);
+ if (!obj)
+ return;
+
+ if (obj->type == ACPI_TYPE_INTEGER && obj->integer.value == 1) {
+ bridge = pci_find_host_bridge(bus);
+ bridge->ignore_reset_delay = 1;
+ }
+ ACPI_FREE(obj);
}
void acpi_pci_remove_bus(struct pci_bus *bus)
@@ -561,6 +591,57 @@ static struct acpi_device *acpi_pci_find_companion(struct device *dev)
check_children);
}
+/**
+ * pci_acpi_optimize_delay - 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 the device itself or the PCI host bridge.
+ *
+ * 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.
+ *
+ * These _DSM functions are defined by the draft ECN of January 28, 2014,
+ * titled "ACPI additions for FW latency optimizations."
+ */
+static void pci_acpi_optimize_delay(struct pci_dev *pdev,
+ acpi_handle handle)
+{
+ struct pci_host_bridge *bridge = pci_find_host_bridge(pdev->bus);
+ int value;
+ union acpi_object *obj, *elements;
+
+ if (bridge->ignore_reset_delay)
+ pdev->d3cold_delay = 0;
+
+ obj = acpi_evaluate_dsm(handle, pci_acpi_dsm_uuid, 3,
+ FUNCTION_DELAY_DSM, NULL);
+ if (!obj)
+ return;
+
+ 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;
+ }
+ }
+ ACPI_FREE(obj);
+}
+
static void pci_acpi_setup(struct device *dev)
{
struct pci_dev *pci_dev = to_pci_dev(dev);
@@ -569,6 +650,8 @@ static void pci_acpi_setup(struct device *dev)
if (!adev)
return;
+ pci_acpi_optimize_delay(pci_dev, adev->handle);
+
pci_acpi_add_pm_notifier(adev, pci_dev);
if (!adev->wakeup.flags.valid)
return;