aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/ssb
diff options
context:
space:
mode:
authorAndrey Skvortsov <andrej.skvortzov@gmail.com>2014-12-04 11:32:46 -0500
committerJohn W. Linville <linville@tuxdriver.com>2014-12-04 11:32:46 -0500
commit5580373fb27706f07be3375c304558980eb90c4e (patch)
treeb747c45d5d56719ddbbe1ac6583eafabe7beae82 /drivers/ssb
parentde51f1649ab77f9ad17bdad581a326cbf6e71b49 (diff)
SSB / B44: fix WOL for BCM4401
Wake On Lan was not working on laptop DELL Vostro 1500. If WOL was turned on, BCM4401 was powered up in suspend mode. LEDs blinked. But the laptop could not be woken up with the Magic Packet. The reason for that was that PCIE was not enabled as a system wakeup source and therefore the host PCI bridge was not powered up in suspend mode. PCIE was not enabled in suspend by PM because no child devices were registered as wakeup source during suspend process. On laptop BCM4401 is connected through the SSB bus, that is connected to the PCI-Express bus. SSB and B44 did not use standard PM wakeup functions and did not forward wakeup settings to their parents. To fix that B44 driver enables PM wakeup and registers new wakeup source using device_set_wakeup_enable(). Wakeup is automatically reported to the parent SSB bus via power.wakeup_path. SSB bus enables wakeup for the parent PCI bridge, if there is any child devices with enabled wakeup functionality. All other steps are done by PM core code. Signed-off-by: Andrey Skvortsov <Andrej.Skvortzov@gmail.com> Signed-off-by: Michael Buesch <m@bues.ch> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/ssb')
-rw-r--r--drivers/ssb/pcihost_wrapper.c33
1 files changed, 22 insertions, 11 deletions
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c
index 69161bbc4d0b..410215c16920 100644
--- a/drivers/ssb/pcihost_wrapper.c
+++ b/drivers/ssb/pcihost_wrapper.c
@@ -11,15 +11,17 @@
11 * Licensed under the GNU/GPL. See COPYING for details. 11 * Licensed under the GNU/GPL. See COPYING for details.
12 */ 12 */
13 13
14#include <linux/pm.h>
14#include <linux/pci.h> 15#include <linux/pci.h>
15#include <linux/export.h> 16#include <linux/export.h>
16#include <linux/slab.h> 17#include <linux/slab.h>
17#include <linux/ssb/ssb.h> 18#include <linux/ssb/ssb.h>
18 19
19 20
20#ifdef CONFIG_PM 21#ifdef CONFIG_PM_SLEEP
21static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) 22static int ssb_pcihost_suspend(struct device *d)
22{ 23{
24 struct pci_dev *dev = to_pci_dev(d);
23 struct ssb_bus *ssb = pci_get_drvdata(dev); 25 struct ssb_bus *ssb = pci_get_drvdata(dev);
24 int err; 26 int err;
25 27
@@ -28,17 +30,23 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state)
28 return err; 30 return err;
29 pci_save_state(dev); 31 pci_save_state(dev);
30 pci_disable_device(dev); 32 pci_disable_device(dev);
31 pci_set_power_state(dev, pci_choose_state(dev, state)); 33
34 /* if there is a wakeup enabled child device on ssb bus,
35 enable pci wakeup posibility. */
36 device_set_wakeup_enable(d, d->power.wakeup_path);
37
38 pci_prepare_to_sleep(dev);
32 39
33 return 0; 40 return 0;
34} 41}
35 42
36static int ssb_pcihost_resume(struct pci_dev *dev) 43static int ssb_pcihost_resume(struct device *d)
37{ 44{
45 struct pci_dev *dev = to_pci_dev(d);
38 struct ssb_bus *ssb = pci_get_drvdata(dev); 46 struct ssb_bus *ssb = pci_get_drvdata(dev);
39 int err; 47 int err;
40 48
41 pci_set_power_state(dev, PCI_D0); 49 pci_back_from_sleep(dev);
42 err = pci_enable_device(dev); 50 err = pci_enable_device(dev);
43 if (err) 51 if (err)
44 return err; 52 return err;
@@ -49,10 +57,12 @@ static int ssb_pcihost_resume(struct pci_dev *dev)
49 57
50 return 0; 58 return 0;
51} 59}
52#else /* CONFIG_PM */ 60
53# define ssb_pcihost_suspend NULL 61static const struct dev_pm_ops ssb_pcihost_pm_ops = {
54# define ssb_pcihost_resume NULL 62 SET_SYSTEM_SLEEP_PM_OPS(ssb_pcihost_suspend, ssb_pcihost_resume)
55#endif /* CONFIG_PM */ 63};
64
65#endif /* CONFIG_PM_SLEEP */
56 66
57static int ssb_pcihost_probe(struct pci_dev *dev, 67static int ssb_pcihost_probe(struct pci_dev *dev,
58 const struct pci_device_id *id) 68 const struct pci_device_id *id)
@@ -115,8 +125,9 @@ int ssb_pcihost_register(struct pci_driver *driver)
115{ 125{
116 driver->probe = ssb_pcihost_probe; 126 driver->probe = ssb_pcihost_probe;
117 driver->remove = ssb_pcihost_remove; 127 driver->remove = ssb_pcihost_remove;
118 driver->suspend = ssb_pcihost_suspend; 128#ifdef CONFIG_PM_SLEEP
119 driver->resume = ssb_pcihost_resume; 129 driver->driver.pm = &ssb_pcihost_pm_ops;
130#endif
120 131
121 return pci_register_driver(driver); 132 return pci_register_driver(driver);
122} 133}