Linux kernel mirror (for testing) git.kernel.org/pub/scm/linux/kernel/git/torvalds/linux.git
kernel os linux

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>

authored by

Michael Buesch and committed by
John W. Linville
8fe2b65a 5100d5ac

+89 -68
+6 -4
drivers/net/wireless/b43/pcmcia.c
··· 43 43 #ifdef CONFIG_PM 44 44 static int b43_pcmcia_suspend(struct pcmcia_device *dev) 45 45 { 46 - //TODO 47 - return 0; 46 + struct ssb_bus *ssb = dev->priv; 47 + 48 + return ssb_bus_suspend(ssb); 48 49 } 49 50 50 51 static int b43_pcmcia_resume(struct pcmcia_device *dev) 51 52 { 52 - //TODO 53 - return 0; 53 + struct ssb_bus *ssb = dev->priv; 54 + 55 + return ssb_bus_resume(ssb); 54 56 } 55 57 #else /* CONFIG_PM */ 56 58 # define b43_pcmcia_suspend NULL
+1 -1
drivers/ssb/driver_chipcommon.c
··· 251 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 256 if (!cc->dev) 257 257 return;
+35 -48
drivers/ssb/main.c
··· 120 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 123 static int ssb_device_resume(struct device *dev) 139 124 { 140 125 struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 141 126 struct ssb_driver *ssb_drv; 142 - struct ssb_bus *bus; 143 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 129 if (dev->driver) { 153 130 ssb_drv = drv_to_ssb_drv(dev->driver); 154 131 if (ssb_drv && ssb_drv->resume) ··· 137 160 return err; 138 161 } 139 162 140 - static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) 141 - { 142 - ssb_chipco_suspend(&bus->chipco, state); 143 - ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); 144 - 145 - /* Reset HW state information in memory, so that HW is 146 - * completely reinitialized on resume. */ 147 - bus->mapped_device = NULL; 148 - #ifdef CONFIG_SSB_DRIVER_PCICORE 149 - bus->pcicore.setup_done = 0; 150 - #endif 151 - #ifdef CONFIG_SSB_DEBUG 152 - bus->powered_up = 0; 153 - #endif 154 - } 155 - 156 163 static int ssb_device_suspend(struct device *dev, pm_message_t state) 157 164 { 158 165 struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); 159 166 struct ssb_driver *ssb_drv; 160 - struct ssb_bus *bus; 161 167 int err = 0; 162 168 163 169 if (dev->driver) { ··· 150 190 if (err) 151 191 goto out; 152 192 } 153 - 154 - bus = ssb_dev->bus; 155 - bus->suspend_cnt++; 156 - if (bus->suspend_cnt == bus->nr_devices) { 157 - /* All devices suspended. Shutdown the bus. */ 158 - ssb_bus_suspend(bus, state); 159 - } 160 - 161 193 out: 162 194 return err; 163 195 } 196 + 197 + int ssb_bus_resume(struct ssb_bus *bus) 198 + { 199 + int err; 200 + 201 + /* Reset HW state information in memory, so that HW is 202 + * completely reinitialized. */ 203 + bus->mapped_device = NULL; 204 + #ifdef CONFIG_SSB_DRIVER_PCICORE 205 + bus->pcicore.setup_done = 0; 206 + #endif 207 + 208 + err = ssb_bus_powerup(bus, 0); 209 + if (err) 210 + return err; 211 + err = ssb_pcmcia_hardware_setup(bus); 212 + if (err) { 213 + ssb_bus_may_powerdown(bus); 214 + return err; 215 + } 216 + ssb_chipco_resume(&bus->chipco); 217 + ssb_bus_may_powerdown(bus); 218 + 219 + return 0; 220 + } 221 + EXPORT_SYMBOL(ssb_bus_resume); 222 + 223 + int ssb_bus_suspend(struct ssb_bus *bus) 224 + { 225 + ssb_chipco_suspend(&bus->chipco); 226 + ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); 227 + 228 + return 0; 229 + } 230 + EXPORT_SYMBOL(ssb_bus_suspend); 164 231 165 232 #ifdef CONFIG_SSB_PCIHOST 166 233 int ssb_devices_freeze(struct ssb_bus *bus)
+10
drivers/ssb/pcihost_wrapper.c
··· 18 18 #ifdef CONFIG_PM 19 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 27 pci_save_state(dev); 22 28 pci_disable_device(dev); 23 29 pci_set_power_state(dev, pci_choose_state(dev, state)); ··· 33 27 34 28 static int ssb_pcihost_resume(struct pci_dev *dev) 35 29 { 30 + struct ssb_bus *ssb = pci_get_drvdata(dev); 36 31 int err; 37 32 38 33 pci_set_power_state(dev, 0); ··· 41 34 if (err) 42 35 return err; 43 36 pci_restore_state(dev); 37 + err = ssb_bus_resume(ssb); 38 + if (err) 39 + return err; 44 40 45 41 return 0; 46 42 }
+24 -10
drivers/ssb/pcmcia.c
··· 684 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 710 void ssb_pcmcia_exit(struct ssb_bus *bus) 688 711 { 689 712 if (bus->bustype != SSB_BUSTYPE_PCMCIA) ··· 722 699 if (bus->bustype != SSB_BUSTYPE_PCMCIA) 723 700 return 0; 724 701 725 - /* Switch segment to a known state and sync 726 - * bus->mapped_pcmcia_seg with hardware state. */ 727 - ssb_pcmcia_switch_segment(bus, 0); 728 - 729 - /* Init the COR register. */ 730 - err = ssb_pcmcia_cor_setup(bus, CISREG_COR); 731 - if (err) 732 - goto error; 733 - /* Some cards also need this register to get poked. */ 734 - err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); 702 + err = ssb_pcmcia_hardware_setup(bus); 735 703 if (err) 736 704 goto error; 737 705
+5
drivers/ssb/ssb_private.h
··· 81 81 u8 seg); 82 82 extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, 83 83 struct ssb_init_invariants *iv); 84 + extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); 84 85 extern void ssb_pcmcia_exit(struct ssb_bus *bus); 85 86 extern int ssb_pcmcia_init(struct ssb_bus *bus); 86 87 extern const struct ssb_bus_ops ssb_pcmcia_ops; ··· 98 97 } 99 98 static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, 100 99 u8 seg) 100 + { 101 + return 0; 102 + } 103 + static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) 101 104 { 102 105 return 0; 103 106 }
+7 -3
include/linux/ssb/ssb.h
··· 260 260 struct ssb_device devices[SSB_MAX_NR_CORES]; 261 261 u8 nr_devices; 262 262 263 - /* Reference count. Number of suspended devices. */ 264 - u8 suspend_cnt; 265 - 266 263 /* Software ID number for this bus. */ 267 264 unsigned int busnumber; 268 265 ··· 330 333 #endif /* CONFIG_SSB_PCMCIAHOST */ 331 334 332 335 extern void ssb_bus_unregister(struct ssb_bus *bus); 336 + 337 + /* Suspend a SSB bus. 338 + * Call this from the parent bus suspend routine. */ 339 + extern int ssb_bus_suspend(struct ssb_bus *bus); 340 + /* Resume a SSB bus. 341 + * Call this from the parent bus resume routine. */ 342 + extern int ssb_bus_resume(struct ssb_bus *bus); 333 343 334 344 extern u32 ssb_clockspeed(struct ssb_bus *bus); 335 345
+1 -2
include/linux/ssb/ssb_driver_chipcommon.h
··· 367 367 368 368 extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); 369 369 370 - #include <linux/pm.h> 371 - extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); 370 + extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); 372 371 extern void ssb_chipco_resume(struct ssb_chipcommon *cc); 373 372 374 373 extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc,