diff options
author | Michael Buesch <mb@bu3sch.de> | 2008-03-29 19:10:50 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2008-04-08 15:05:57 -0400 |
commit | 8fe2b65a18e49bfde56a59ed4ab3fc7aa0c2f325 (patch) | |
tree | a813fe635b7a8c248c586de847d1501c4ccaab6b | |
parent | 5100d5ac81b9330dc57e35adbe50923ba6107b8f (diff) |
ssb: Turn suspend/resume upside down
Turn the SSB bus suspend mechanism upside down.
Instead of deciding by an internal reference count when to suspend/resume,
let the parent bus call us in their suspend/resume routine.
Signed-off-by: Michael Buesch <mb@bu3sch.de>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
-rw-r--r-- | drivers/net/wireless/b43/pcmcia.c | 10 | ||||
-rw-r--r-- | drivers/ssb/driver_chipcommon.c | 2 | ||||
-rw-r--r-- | drivers/ssb/main.c | 81 | ||||
-rw-r--r-- | drivers/ssb/pcihost_wrapper.c | 10 | ||||
-rw-r--r-- | drivers/ssb/pcmcia.c | 34 | ||||
-rw-r--r-- | drivers/ssb/ssb_private.h | 5 | ||||
-rw-r--r-- | include/linux/ssb/ssb.h | 10 | ||||
-rw-r--r-- | include/linux/ssb/ssb_driver_chipcommon.h | 3 |
8 files changed, 88 insertions, 67 deletions
diff --git a/drivers/net/wireless/b43/pcmcia.c b/drivers/net/wireless/b43/pcmcia.c index 371e4a119511..b8aa16307f79 100644 --- a/drivers/net/wireless/b43/pcmcia.c +++ b/drivers/net/wireless/b43/pcmcia.c | |||
@@ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); | |||
43 | #ifdef CONFIG_PM | 43 | #ifdef CONFIG_PM |
44 | static int b43_pcmcia_suspend(struct pcmcia_device *dev) | 44 | static int b43_pcmcia_suspend(struct pcmcia_device *dev) |
45 | { | 45 | { |
46 | //TODO | 46 | struct ssb_bus *ssb = dev->priv; |
47 | return 0; | 47 | |
48 | return ssb_bus_suspend(ssb); | ||
48 | } | 49 | } |
49 | 50 | ||
50 | static int b43_pcmcia_resume(struct pcmcia_device *dev) | 51 | static int b43_pcmcia_resume(struct pcmcia_device *dev) |
51 | { | 52 | { |
52 | //TODO | 53 | struct ssb_bus *ssb = dev->priv; |
53 | return 0; | 54 | |
55 | return ssb_bus_resume(ssb); | ||
54 | } | 56 | } |
55 | #else /* CONFIG_PM */ | 57 | #else /* CONFIG_PM */ |
56 | # define b43_pcmcia_suspend NULL | 58 | # define b43_pcmcia_suspend NULL |
diff --git a/drivers/ssb/driver_chipcommon.c b/drivers/ssb/driver_chipcommon.c index 45b672a69003..571f4fd55236 100644 --- a/drivers/ssb/driver_chipcommon.c +++ b/drivers/ssb/driver_chipcommon.c | |||
@@ -251,7 +251,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) | |||
251 | calc_fast_powerup_delay(cc); | 251 | calc_fast_powerup_delay(cc); |
252 | } | 252 | } |
253 | 253 | ||
254 | void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) | 254 | void ssb_chipco_suspend(struct ssb_chipcommon *cc) |
255 | { | 255 | { |
256 | if (!cc->dev) | 256 | if (!cc->dev) |
257 | return; | 257 | return; |
diff --git a/drivers/ssb/main.c b/drivers/ssb/main.c index 2fcfd73b3b6e..c0cbdba07aee 100644 --- a/drivers/ssb/main.c +++ b/drivers/ssb/main.c | |||
@@ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev) | |||
120 | put_device(dev->dev); | 120 | put_device(dev->dev); |
121 | } | 121 | } |
122 | 122 | ||
123 | static int ssb_bus_resume(struct ssb_bus *bus) | ||
124 | { | ||
125 | int err; | ||
126 | |||
127 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||
128 | err = ssb_pcmcia_init(bus); | ||
129 | if (err) { | ||
130 | /* No need to disable XTAL, as we don't have one on PCMCIA. */ | ||
131 | return err; | ||
132 | } | ||
133 | ssb_chipco_resume(&bus->chipco); | ||
134 | |||
135 | return 0; | ||
136 | } | ||
137 | |||
138 | static int ssb_device_resume(struct device *dev) | 123 | static int ssb_device_resume(struct device *dev) |
139 | { | 124 | { |
140 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 125 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
141 | struct ssb_driver *ssb_drv; | 126 | struct ssb_driver *ssb_drv; |
142 | struct ssb_bus *bus; | ||
143 | int err = 0; | 127 | int err = 0; |
144 | 128 | ||
145 | bus = ssb_dev->bus; | ||
146 | if (bus->suspend_cnt == bus->nr_devices) { | ||
147 | err = ssb_bus_resume(bus); | ||
148 | if (err) | ||
149 | return err; | ||
150 | } | ||
151 | bus->suspend_cnt--; | ||
152 | if (dev->driver) { | 129 | if (dev->driver) { |
153 | ssb_drv = drv_to_ssb_drv(dev->driver); | 130 | ssb_drv = drv_to_ssb_drv(dev->driver); |
154 | if (ssb_drv && ssb_drv->resume) | 131 | if (ssb_drv && ssb_drv->resume) |
@@ -160,27 +137,10 @@ out: | |||
160 | return err; | 137 | return err; |
161 | } | 138 | } |
162 | 139 | ||
163 | static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) | ||
164 | { | ||
165 | ssb_chipco_suspend(&bus->chipco, state); | ||
166 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
167 | |||
168 | /* Reset HW state information in memory, so that HW is | ||
169 | * completely reinitialized on resume. */ | ||
170 | bus->mapped_device = NULL; | ||
171 | #ifdef CONFIG_SSB_DRIVER_PCICORE | ||
172 | bus->pcicore.setup_done = 0; | ||
173 | #endif | ||
174 | #ifdef CONFIG_SSB_DEBUG | ||
175 | bus->powered_up = 0; | ||
176 | #endif | ||
177 | } | ||
178 | |||
179 | static int ssb_device_suspend(struct device *dev, pm_message_t state) | 140 | static int ssb_device_suspend(struct device *dev, pm_message_t state) |
180 | { | 141 | { |
181 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | 142 | struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); |
182 | struct ssb_driver *ssb_drv; | 143 | struct ssb_driver *ssb_drv; |
183 | struct ssb_bus *bus; | ||
184 | int err = 0; | 144 | int err = 0; |
185 | 145 | ||
186 | if (dev->driver) { | 146 | if (dev->driver) { |
@@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) | |||
190 | if (err) | 150 | if (err) |
191 | goto out; | 151 | goto out; |
192 | } | 152 | } |
153 | out: | ||
154 | return err; | ||
155 | } | ||
156 | |||
157 | int ssb_bus_resume(struct ssb_bus *bus) | ||
158 | { | ||
159 | int err; | ||
193 | 160 | ||
194 | bus = ssb_dev->bus; | 161 | /* Reset HW state information in memory, so that HW is |
195 | bus->suspend_cnt++; | 162 | * completely reinitialized. */ |
196 | if (bus->suspend_cnt == bus->nr_devices) { | 163 | bus->mapped_device = NULL; |
197 | /* All devices suspended. Shutdown the bus. */ | 164 | #ifdef CONFIG_SSB_DRIVER_PCICORE |
198 | ssb_bus_suspend(bus, state); | 165 | bus->pcicore.setup_done = 0; |
166 | #endif | ||
167 | |||
168 | err = ssb_bus_powerup(bus, 0); | ||
169 | if (err) | ||
170 | return err; | ||
171 | err = ssb_pcmcia_hardware_setup(bus); | ||
172 | if (err) { | ||
173 | ssb_bus_may_powerdown(bus); | ||
174 | return err; | ||
199 | } | 175 | } |
176 | ssb_chipco_resume(&bus->chipco); | ||
177 | ssb_bus_may_powerdown(bus); | ||
200 | 178 | ||
201 | out: | 179 | return 0; |
202 | return err; | 180 | } |
181 | EXPORT_SYMBOL(ssb_bus_resume); | ||
182 | |||
183 | int ssb_bus_suspend(struct ssb_bus *bus) | ||
184 | { | ||
185 | ssb_chipco_suspend(&bus->chipco); | ||
186 | ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||
187 | |||
188 | return 0; | ||
203 | } | 189 | } |
190 | EXPORT_SYMBOL(ssb_bus_suspend); | ||
204 | 191 | ||
205 | #ifdef CONFIG_SSB_PCIHOST | 192 | #ifdef CONFIG_SSB_PCIHOST |
206 | int ssb_devices_freeze(struct ssb_bus *bus) | 193 | int ssb_devices_freeze(struct ssb_bus *bus) |
diff --git a/drivers/ssb/pcihost_wrapper.c b/drivers/ssb/pcihost_wrapper.c index 82a10abef640..e82db4aaa050 100644 --- a/drivers/ssb/pcihost_wrapper.c +++ b/drivers/ssb/pcihost_wrapper.c | |||
@@ -18,6 +18,12 @@ | |||
18 | #ifdef CONFIG_PM | 18 | #ifdef CONFIG_PM |
19 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | 19 | static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) |
20 | { | 20 | { |
21 | struct ssb_bus *ssb = pci_get_drvdata(dev); | ||
22 | int err; | ||
23 | |||
24 | err = ssb_bus_suspend(ssb); | ||
25 | if (err) | ||
26 | return err; | ||
21 | pci_save_state(dev); | 27 | pci_save_state(dev); |
22 | pci_disable_device(dev); | 28 | pci_disable_device(dev); |
23 | pci_set_power_state(dev, pci_choose_state(dev, state)); | 29 | pci_set_power_state(dev, pci_choose_state(dev, state)); |
@@ -27,6 +33,7 @@ static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | |||
27 | 33 | ||
28 | static int ssb_pcihost_resume(struct pci_dev *dev) | 34 | static int ssb_pcihost_resume(struct pci_dev *dev) |
29 | { | 35 | { |
36 | struct ssb_bus *ssb = pci_get_drvdata(dev); | ||
30 | int err; | 37 | int err; |
31 | 38 | ||
32 | pci_set_power_state(dev, 0); | 39 | pci_set_power_state(dev, 0); |
@@ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev) | |||
34 | if (err) | 41 | if (err) |
35 | return err; | 42 | return err; |
36 | pci_restore_state(dev); | 43 | pci_restore_state(dev); |
44 | err = ssb_bus_resume(ssb); | ||
45 | if (err) | ||
46 | return err; | ||
37 | 47 | ||
38 | return 0; | 48 | return 0; |
39 | } | 49 | } |
diff --git a/drivers/ssb/pcmcia.c b/drivers/ssb/pcmcia.c index d674cef7210d..dcaf2412bea7 100644 --- a/drivers/ssb/pcmcia.c +++ b/drivers/ssb/pcmcia.c | |||
@@ -684,6 +684,29 @@ static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor) | |||
684 | return 0; | 684 | return 0; |
685 | } | 685 | } |
686 | 686 | ||
687 | /* Initialize the PCMCIA hardware. This is called on Init and Resume. */ | ||
688 | int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||
689 | { | ||
690 | int err; | ||
691 | |||
692 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||
693 | return 0; | ||
694 | |||
695 | /* Switch segment to a known state and sync | ||
696 | * bus->mapped_pcmcia_seg with hardware state. */ | ||
697 | ssb_pcmcia_switch_segment(bus, 0); | ||
698 | /* Init the COR register. */ | ||
699 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||
700 | if (err) | ||
701 | return err; | ||
702 | /* Some cards also need this register to get poked. */ | ||
703 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||
704 | if (err) | ||
705 | return err; | ||
706 | |||
707 | return 0; | ||
708 | } | ||
709 | |||
687 | void ssb_pcmcia_exit(struct ssb_bus *bus) | 710 | void ssb_pcmcia_exit(struct ssb_bus *bus) |
688 | { | 711 | { |
689 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | 712 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) |
@@ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus) | |||
699 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) | 722 | if (bus->bustype != SSB_BUSTYPE_PCMCIA) |
700 | return 0; | 723 | return 0; |
701 | 724 | ||
702 | /* Switch segment to a known state and sync | 725 | err = ssb_pcmcia_hardware_setup(bus); |
703 | * bus->mapped_pcmcia_seg with hardware state. */ | ||
704 | ssb_pcmcia_switch_segment(bus, 0); | ||
705 | |||
706 | /* Init the COR register. */ | ||
707 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||
708 | if (err) | ||
709 | goto error; | ||
710 | /* Some cards also need this register to get poked. */ | ||
711 | err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||
712 | if (err) | 726 | if (err) |
713 | goto error; | 727 | goto error; |
714 | 728 | ||
diff --git a/drivers/ssb/ssb_private.h b/drivers/ssb/ssb_private.h index a83bf7a4d80b..ebc32d8fe15f 100644 --- a/drivers/ssb/ssb_private.h +++ b/drivers/ssb/ssb_private.h | |||
@@ -81,6 +81,7 @@ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | |||
81 | u8 seg); | 81 | u8 seg); |
82 | extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | 82 | extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, |
83 | struct ssb_init_invariants *iv); | 83 | struct ssb_init_invariants *iv); |
84 | extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); | ||
84 | extern void ssb_pcmcia_exit(struct ssb_bus *bus); | 85 | extern void ssb_pcmcia_exit(struct ssb_bus *bus); |
85 | extern int ssb_pcmcia_init(struct ssb_bus *bus); | 86 | extern int ssb_pcmcia_init(struct ssb_bus *bus); |
86 | extern const struct ssb_bus_ops ssb_pcmcia_ops; | 87 | extern const struct ssb_bus_ops ssb_pcmcia_ops; |
@@ -100,6 +101,10 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | |||
100 | { | 101 | { |
101 | return 0; | 102 | return 0; |
102 | } | 103 | } |
104 | static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||
105 | { | ||
106 | return 0; | ||
107 | } | ||
103 | static inline void ssb_pcmcia_exit(struct ssb_bus *bus) | 108 | static inline void ssb_pcmcia_exit(struct ssb_bus *bus) |
104 | { | 109 | { |
105 | } | 110 | } |
diff --git a/include/linux/ssb/ssb.h b/include/linux/ssb/ssb.h index 8644e03cf588..a8ca396f810a 100644 --- a/include/linux/ssb/ssb.h +++ b/include/linux/ssb/ssb.h | |||
@@ -260,9 +260,6 @@ struct ssb_bus { | |||
260 | struct ssb_device devices[SSB_MAX_NR_CORES]; | 260 | struct ssb_device devices[SSB_MAX_NR_CORES]; |
261 | u8 nr_devices; | 261 | u8 nr_devices; |
262 | 262 | ||
263 | /* Reference count. Number of suspended devices. */ | ||
264 | u8 suspend_cnt; | ||
265 | |||
266 | /* Software ID number for this bus. */ | 263 | /* Software ID number for this bus. */ |
267 | unsigned int busnumber; | 264 | unsigned int busnumber; |
268 | 265 | ||
@@ -334,6 +331,13 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | |||
334 | 331 | ||
335 | extern void ssb_bus_unregister(struct ssb_bus *bus); | 332 | extern void ssb_bus_unregister(struct ssb_bus *bus); |
336 | 333 | ||
334 | /* Suspend a SSB bus. | ||
335 | * Call this from the parent bus suspend routine. */ | ||
336 | extern int ssb_bus_suspend(struct ssb_bus *bus); | ||
337 | /* Resume a SSB bus. | ||
338 | * Call this from the parent bus resume routine. */ | ||
339 | extern int ssb_bus_resume(struct ssb_bus *bus); | ||
340 | |||
337 | extern u32 ssb_clockspeed(struct ssb_bus *bus); | 341 | extern u32 ssb_clockspeed(struct ssb_bus *bus); |
338 | 342 | ||
339 | /* Is the device enabled in hardware? */ | 343 | /* Is the device enabled in hardware? */ |
diff --git a/include/linux/ssb/ssb_driver_chipcommon.h b/include/linux/ssb/ssb_driver_chipcommon.h index b548a54ff1f5..7d7e03dcf77c 100644 --- a/include/linux/ssb/ssb_driver_chipcommon.h +++ b/include/linux/ssb/ssb_driver_chipcommon.h | |||
@@ -367,8 +367,7 @@ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) | |||
367 | 367 | ||
368 | extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); | 368 | extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); |
369 | 369 | ||
370 | #include <linux/pm.h> | 370 | extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); |
371 | extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); | ||
372 | extern void ssb_chipco_resume(struct ssb_chipcommon *cc); | 371 | extern void ssb_chipco_resume(struct ssb_chipcommon *cc); |
373 | 372 | ||
374 | extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, | 373 | extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, |