aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/pci/pcie/portdrv_core.c
diff options
context:
space:
mode:
authorLukas Wunner <lukas@wunner.de>2018-07-19 17:27:53 -0500
committerBjorn Helgaas <bhelgaas@google.com>2018-07-31 11:07:59 -0500
commit7903782460ee1813d6779c968b28d0ac71b9b3ae (patch)
treec546ddf42c07930455290c41d12cd338160e15af /drivers/pci/pcie/portdrv_core.c
parentPCI: portdrv: Deduplicate PM callback iterator (diff)
downloadlinux-dev-7903782460ee1813d6779c968b28d0ac71b9b3ae.tar.xz
linux-dev-7903782460ee1813d6779c968b28d0ac71b9b3ae.zip
PCI: pciehp: Clear spurious events earlier on resume
Thunderbolt hotplug ports that were occupied before system sleep resume with their downstream link in "off" state. Only after the Thunderbolt controller has reestablished the PCIe tunnels does the link go up. As a result, a spurious Presence Detect Changed and/or Data Link Layer State Changed event occurs. The events are not immediately acted upon because tunnel reestablishment happens in the ->resume_noirq phase, when interrupts are still disabled. Also, notification of events may initially be disabled in the Slot Control register when coming out of system sleep and is reenabled in the ->resume_noirq phase through: pci_pm_resume_noirq() pci_pm_default_resume_early() pci_restore_state() pci_restore_pcie_state() It is not guaranteed that the events are acted upon at all: PCIe r4.0, sec 6.7.3.4 says that "a port may optionally send an MSI when there are hot-plug events that occur while interrupt generation is disabled, and interrupt generation is subsequently enabled." Note the "optionally". If an MSI is sent, pciehp will gratuitously turn the slot off and back on once the ->resume_early phase has commenced. If an MSI is not sent, the extant, unacknowledged events in the Slot Status register will prevent future notification of presence or link changes. Commit 13c65840feab ("PCI: pciehp: Clear Presence Detect and Data Link Layer Status Changed on resume") fixed the latter by clearing the events in the ->resume phase. Move this to the ->resume_noirq phase to also fix the gratuitous disable/enablement of the slot. The commit further restored the Slot Control register in the ->resume phase, but that's dispensable because as shown above it's already been done in the ->resume_noirq phase. Signed-off-by: Lukas Wunner <lukas@wunner.de> Signed-off-by: Bjorn Helgaas <bhelgaas@google.com> Cc: Mika Westerberg <mika.westerberg@linux.intel.com>
Diffstat (limited to 'drivers/pci/pcie/portdrv_core.c')
-rw-r--r--drivers/pci/pcie/portdrv_core.c6
1 files changed, 6 insertions, 0 deletions
diff --git a/drivers/pci/pcie/portdrv_core.c b/drivers/pci/pcie/portdrv_core.c
index 13a248575a14..7c37d815229e 100644
--- a/drivers/pci/pcie/portdrv_core.c
+++ b/drivers/pci/pcie/portdrv_core.c
@@ -380,6 +380,12 @@ int pcie_port_device_suspend(struct device *dev)
return device_for_each_child(dev, &off, pm_iter);
}
+int pcie_port_device_resume_noirq(struct device *dev)
+{
+ size_t off = offsetof(struct pcie_port_service_driver, resume_noirq);
+ return device_for_each_child(dev, &off, pm_iter);
+}
+
/**
* pcie_port_device_resume - resume port services associated with a PCIe port
* @dev: PCI Express port to handle