diff options
author | Kai Heng Feng <kai.heng.feng@canonical.com> | 2018-05-07 02:11:20 -0400 |
---|---|---|
committer | Rafael J. Wysocki <rafael.j.wysocki@intel.com> | 2018-05-09 06:26:42 -0400 |
commit | 8feaec33b9868582654cd3d5355225dcb79aeca6 (patch) | |
tree | 146b2c055dd4ede6143b7fcb17577300c6aef480 | |
parent | 75bc37fefc4471e718ba8e651aa74673d4e0a9eb (diff) |
PCI / PM: Always check PME wakeup capability for runtime wakeup support
USB controller ASM1042 stops working after commit de3ef1eb1cd0 (PM /
core: Drop run_wake flag from struct dev_pm_info).
The device in question is not power managed by platform firmware,
furthermore, it only supports PME# from D3cold:
Capabilities: [78] Power Management version 3
Flags: PMEClk- DSI- D1- D2- AuxCurrent=55mA PME(D0-,D1-,D2-,D3hot-,D3cold+)
Status: D0 NoSoftRst+ PME-Enable- DSel=0 DScale=0 PME-
Before commit de3ef1eb1cd0, the device never gets runtime suspended.
After that commit, the device gets runtime suspended to D3hot, which can
not generate any PME#.
usb_hcd_pci_probe() unconditionally calls device_wakeup_enable(), hence
device_can_wakeup() in pci_dev_run_wake() always returns true.
So pci_dev_run_wake() needs to check PME wakeup capability as its first
condition.
In addition, change wakeup flag passed to pci_target_state() from false
to true, because we want to find the deepest state different from D3cold
that the device can still generate PME#. In this case, it's D0 for the
device in question.
Fixes: de3ef1eb1cd0 (PM / core: Drop run_wake flag from struct dev_pm_info)
Signed-off-by: Kai-Heng Feng <kai.heng.feng@canonical.com>
Cc: 4.13+ <stable@vger.kernel.org> # 4.13+
Acked-by: Bjorn Helgaas <bhelgaas@google.com>
Signed-off-by: Rafael J. Wysocki <rafael.j.wysocki@intel.com>
-rw-r--r-- | drivers/pci/pci.c | 8 |
1 files changed, 4 insertions, 4 deletions
diff --git a/drivers/pci/pci.c b/drivers/pci/pci.c index a04197ce767d..c2616cad3a1d 100644 --- a/drivers/pci/pci.c +++ b/drivers/pci/pci.c | |||
@@ -2138,16 +2138,16 @@ bool pci_dev_run_wake(struct pci_dev *dev) | |||
2138 | { | 2138 | { |
2139 | struct pci_bus *bus = dev->bus; | 2139 | struct pci_bus *bus = dev->bus; |
2140 | 2140 | ||
2141 | if (device_can_wakeup(&dev->dev)) | ||
2142 | return true; | ||
2143 | |||
2144 | if (!dev->pme_support) | 2141 | if (!dev->pme_support) |
2145 | return false; | 2142 | return false; |
2146 | 2143 | ||
2147 | /* PME-capable in principle, but not from the target power state */ | 2144 | /* PME-capable in principle, but not from the target power state */ |
2148 | if (!pci_pme_capable(dev, pci_target_state(dev, false))) | 2145 | if (!pci_pme_capable(dev, pci_target_state(dev, true))) |
2149 | return false; | 2146 | return false; |
2150 | 2147 | ||
2148 | if (device_can_wakeup(&dev->dev)) | ||
2149 | return true; | ||
2150 | |||
2151 | while (bus->parent) { | 2151 | while (bus->parent) { |
2152 | struct pci_dev *bridge = bus->self; | 2152 | struct pci_dev *bridge = bus->self; |
2153 | 2153 | ||