aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-07-11 21:05:39 -0400
committerRafael J. Wysocki <rafael.j.wysocki@intel.com>2017-07-12 17:09:21 -0400
commit0ce3fcaff92908c370334ce3b9111aeea71159d6 (patch)
treeb60bc7ee980415b48df2bb167f2c5ee1efe0d6e9
parentde3ef1eb1cd0cc3a75f7a3661e10ed827f370ab8 (diff)
PCI / PM: Restore PME Enable after config space restoration
Commit dc15e71eefc7 (PCI / PM: Restore PME Enable if skipping wakeup setup) introduced a mechanism by which the PME Enable bit can be restored by pci_enable_wake() if dev->wakeup_prepared is set in case it has been overwritten by PCI config space restoration. However, that commit overlooked the fact that on some systems (Dell XPS13 9360 in particular) the AML handling wakeup events checks PME Status and PME Enable and it won't trigger a Notify() for devices where those bits are not set while it is running. That happens during resume from suspend-to-idle when pci_restore_state() invoked by pci_pm_default_resume_early() clears PME Enable before the wakeup events are processed by AML, effectively causing those wakeup events to be ignored. Fix this issue by restoring the PME Enable configuration right after pci_restore_state() has been called instead of doing that in pci_enable_wake(). Fixes: dc15e71eefc7 (PCI / PM: Restore PME Enable if skipping wakeup setup) Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com> Acked-by: Bjorn Helgaas <bhelgaas@google.com>
-rw-r--r--drivers/pci/pci-driver.c2
-rw-r--r--drivers/pci/pci.c16
-rw-r--r--drivers/pci/pci.h1
3 files changed, 11 insertions, 8 deletions
diff --git a/drivers/pci/pci-driver.c b/drivers/pci/pci-driver.c
index ffe7d54d9328..1a93b48b0dd9 100644
--- a/drivers/pci/pci-driver.c
+++ b/drivers/pci/pci-driver.c
@@ -506,6 +506,7 @@ static int pci_restore_standard_config(struct pci_dev *pci_dev)
506 } 506 }
507 507
508 pci_restore_state(pci_dev); 508 pci_restore_state(pci_dev);
509 pci_pme_restore(pci_dev);
509 return 0; 510 return 0;
510} 511}
511 512
@@ -517,6 +518,7 @@ static void pci_pm_default_resume_early(struct pci_dev *pci_dev)
517{ 518{
518 pci_power_up(pci_dev); 519 pci_power_up(pci_dev);
519 pci_restore_state(pci_dev); 520 pci_restore_state(pci_dev);
521 pci_pme_restore(pci_dev);
520 pci_fixup_device(pci_fixup_resume_early, pci_dev); 522 pci_fixup_device(pci_fixup_resume_early, pci_dev);
521} 523}
522 524
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c
index 0b5302a9fdae..d1443a161b35 100644
--- a/drivers/pci/pci.c
+++ b/drivers/pci/pci.c
@@ -1798,7 +1798,11 @@ static void __pci_pme_active(struct pci_dev *dev, bool enable)
1798 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr); 1798 pci_write_config_word(dev, dev->pm_cap + PCI_PM_CTRL, pmcsr);
1799} 1799}
1800 1800
1801static void pci_pme_restore(struct pci_dev *dev) 1801/**
1802 * pci_pme_restore - Restore PME configuration after config space restore.
1803 * @dev: PCI device to update.
1804 */
1805void pci_pme_restore(struct pci_dev *dev)
1802{ 1806{
1803 u16 pmcsr; 1807 u16 pmcsr;
1804 1808
@@ -1808,6 +1812,7 @@ static void pci_pme_restore(struct pci_dev *dev)
1808 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr); 1812 pci_read_config_word(dev, dev->pm_cap + PCI_PM_CTRL, &pmcsr);
1809 if (dev->wakeup_prepared) { 1813 if (dev->wakeup_prepared) {
1810 pmcsr |= PCI_PM_CTRL_PME_ENABLE; 1814 pmcsr |= PCI_PM_CTRL_PME_ENABLE;
1815 pmcsr &= ~PCI_PM_CTRL_PME_STATUS;
1811 } else { 1816 } else {
1812 pmcsr &= ~PCI_PM_CTRL_PME_ENABLE; 1817 pmcsr &= ~PCI_PM_CTRL_PME_ENABLE;
1813 pmcsr |= PCI_PM_CTRL_PME_STATUS; 1818 pmcsr |= PCI_PM_CTRL_PME_STATUS;
@@ -1904,14 +1909,9 @@ int pci_enable_wake(struct pci_dev *dev, pci_power_t state, bool enable)
1904{ 1909{
1905 int ret = 0; 1910 int ret = 0;
1906 1911
1907 /* 1912 /* Don't do the same thing twice in a row for one device. */
1908 * Don't do the same thing twice in a row for one device, but restore 1913 if (!!enable == !!dev->wakeup_prepared)
1909 * PME Enable in case it has been updated by config space restoration.
1910 */
1911 if (!!enable == !!dev->wakeup_prepared) {
1912 pci_pme_restore(dev);
1913 return 0; 1914 return 0;
1914 }
1915 1915
1916 /* 1916 /*
1917 * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don 1917 * According to "PCI System Architecture" 4th ed. by Tom Shanley & Don
diff --git a/drivers/pci/pci.h b/drivers/pci/pci.h
index 240b2c0fed4b..0a6e737f5325 100644
--- a/drivers/pci/pci.h
+++ b/drivers/pci/pci.h
@@ -71,6 +71,7 @@ void pci_power_up(struct pci_dev *dev);
71void pci_disable_enabled_device(struct pci_dev *dev); 71void pci_disable_enabled_device(struct pci_dev *dev);
72int pci_finish_runtime_suspend(struct pci_dev *dev); 72int pci_finish_runtime_suspend(struct pci_dev *dev);
73int __pci_pme_wakeup(struct pci_dev *dev, void *ign); 73int __pci_pme_wakeup(struct pci_dev *dev, void *ign);
74void pci_pme_restore(struct pci_dev *dev);
74bool pci_dev_keep_suspended(struct pci_dev *dev); 75bool pci_dev_keep_suspended(struct pci_dev *dev);
75void pci_dev_complete_resume(struct pci_dev *pci_dev); 76void pci_dev_complete_resume(struct pci_dev *pci_dev);
76void pci_config_pm_runtime_get(struct pci_dev *dev); 77void pci_config_pm_runtime_get(struct pci_dev *dev);