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>
This commit is contained in:
		
							parent
							
								
									5100d5ac81
								
							
						
					
					
						commit
						8fe2b65a18
					
				| @ -43,14 +43,16 @@ MODULE_DEVICE_TABLE(pcmcia, b43_pcmcia_tbl); | ||||
| #ifdef CONFIG_PM | ||||
| static int b43_pcmcia_suspend(struct pcmcia_device *dev) | ||||
| { | ||||
| 	//TODO
 | ||||
| 	return 0; | ||||
| 	struct ssb_bus *ssb = dev->priv; | ||||
| 
 | ||||
| 	return ssb_bus_suspend(ssb); | ||||
| } | ||||
| 
 | ||||
| static int b43_pcmcia_resume(struct pcmcia_device *dev) | ||||
| { | ||||
| 	//TODO
 | ||||
| 	return 0; | ||||
| 	struct ssb_bus *ssb = dev->priv; | ||||
| 
 | ||||
| 	return ssb_bus_resume(ssb); | ||||
| } | ||||
| #else /* CONFIG_PM */ | ||||
| # define b43_pcmcia_suspend		NULL | ||||
|  | ||||
| @ -251,7 +251,7 @@ void ssb_chipcommon_init(struct ssb_chipcommon *cc) | ||||
| 	calc_fast_powerup_delay(cc); | ||||
| } | ||||
| 
 | ||||
| void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state) | ||||
| void ssb_chipco_suspend(struct ssb_chipcommon *cc) | ||||
| { | ||||
| 	if (!cc->dev) | ||||
| 		return; | ||||
|  | ||||
| @ -120,35 +120,12 @@ static void ssb_device_put(struct ssb_device *dev) | ||||
| 		put_device(dev->dev); | ||||
| } | ||||
| 
 | ||||
| static int ssb_bus_resume(struct ssb_bus *bus) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 1); | ||||
| 	err = ssb_pcmcia_init(bus); | ||||
| 	if (err) { | ||||
| 		/* No need to disable XTAL, as we don't have one on PCMCIA. */ | ||||
| 		return err; | ||||
| 	} | ||||
| 	ssb_chipco_resume(&bus->chipco); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| static int ssb_device_resume(struct device *dev) | ||||
| { | ||||
| 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||||
| 	struct ssb_driver *ssb_drv; | ||||
| 	struct ssb_bus *bus; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	bus = ssb_dev->bus; | ||||
| 	if (bus->suspend_cnt == bus->nr_devices) { | ||||
| 		err = ssb_bus_resume(bus); | ||||
| 		if (err) | ||||
| 			return err; | ||||
| 	} | ||||
| 	bus->suspend_cnt--; | ||||
| 	if (dev->driver) { | ||||
| 		ssb_drv = drv_to_ssb_drv(dev->driver); | ||||
| 		if (ssb_drv && ssb_drv->resume) | ||||
| @ -160,27 +137,10 @@ out: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| static void ssb_bus_suspend(struct ssb_bus *bus, pm_message_t state) | ||||
| { | ||||
| 	ssb_chipco_suspend(&bus->chipco, state); | ||||
| 	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||||
| 
 | ||||
| 	/* Reset HW state information in memory, so that HW is
 | ||||
| 	 * completely reinitialized on resume. */ | ||||
| 	bus->mapped_device = NULL; | ||||
| #ifdef CONFIG_SSB_DRIVER_PCICORE | ||||
| 	bus->pcicore.setup_done = 0; | ||||
| #endif | ||||
| #ifdef CONFIG_SSB_DEBUG | ||||
| 	bus->powered_up = 0; | ||||
| #endif | ||||
| } | ||||
| 
 | ||||
| static int ssb_device_suspend(struct device *dev, pm_message_t state) | ||||
| { | ||||
| 	struct ssb_device *ssb_dev = dev_to_ssb_dev(dev); | ||||
| 	struct ssb_driver *ssb_drv; | ||||
| 	struct ssb_bus *bus; | ||||
| 	int err = 0; | ||||
| 
 | ||||
| 	if (dev->driver) { | ||||
| @ -190,18 +150,45 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state) | ||||
| 		if (err) | ||||
| 			goto out; | ||||
| 	} | ||||
| 
 | ||||
| 	bus = ssb_dev->bus; | ||||
| 	bus->suspend_cnt++; | ||||
| 	if (bus->suspend_cnt == bus->nr_devices) { | ||||
| 		/* All devices suspended. Shutdown the bus. */ | ||||
| 		ssb_bus_suspend(bus, state); | ||||
| 	} | ||||
| 
 | ||||
| out: | ||||
| 	return err; | ||||
| } | ||||
| 
 | ||||
| int ssb_bus_resume(struct ssb_bus *bus) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	/* Reset HW state information in memory, so that HW is
 | ||||
| 	 * completely reinitialized. */ | ||||
| 	bus->mapped_device = NULL; | ||||
| #ifdef CONFIG_SSB_DRIVER_PCICORE | ||||
| 	bus->pcicore.setup_done = 0; | ||||
| #endif | ||||
| 
 | ||||
| 	err = ssb_bus_powerup(bus, 0); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	err = ssb_pcmcia_hardware_setup(bus); | ||||
| 	if (err) { | ||||
| 		ssb_bus_may_powerdown(bus); | ||||
| 		return err; | ||||
| 	} | ||||
| 	ssb_chipco_resume(&bus->chipco); | ||||
| 	ssb_bus_may_powerdown(bus); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ssb_bus_resume); | ||||
| 
 | ||||
| int ssb_bus_suspend(struct ssb_bus *bus) | ||||
| { | ||||
| 	ssb_chipco_suspend(&bus->chipco); | ||||
| 	ssb_pci_xtal(bus, SSB_GPIO_XTAL | SSB_GPIO_PLL, 0); | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| EXPORT_SYMBOL(ssb_bus_suspend); | ||||
| 
 | ||||
| #ifdef CONFIG_SSB_PCIHOST | ||||
| int ssb_devices_freeze(struct ssb_bus *bus) | ||||
| { | ||||
|  | ||||
| @ -18,6 +18,12 @@ | ||||
| #ifdef CONFIG_PM | ||||
| static int ssb_pcihost_suspend(struct pci_dev *dev, pm_message_t state) | ||||
| { | ||||
| 	struct ssb_bus *ssb = pci_get_drvdata(dev); | ||||
| 	int err; | ||||
| 
 | ||||
| 	err = ssb_bus_suspend(ssb); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	pci_save_state(dev); | ||||
| 	pci_disable_device(dev); | ||||
| 	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) | ||||
| 
 | ||||
| static int ssb_pcihost_resume(struct pci_dev *dev) | ||||
| { | ||||
| 	struct ssb_bus *ssb = pci_get_drvdata(dev); | ||||
| 	int err; | ||||
| 
 | ||||
| 	pci_set_power_state(dev, 0); | ||||
| @ -34,6 +41,9 @@ static int ssb_pcihost_resume(struct pci_dev *dev) | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	pci_restore_state(dev); | ||||
| 	err = ssb_bus_resume(ssb); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
|  | ||||
| @ -684,6 +684,29 @@ static int ssb_pcmcia_cor_setup(struct ssb_bus *bus, u8 cor) | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| /* Initialize the PCMCIA hardware. This is called on Init and Resume. */ | ||||
| int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||||
| { | ||||
| 	int err; | ||||
| 
 | ||||
| 	if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* Switch segment to a known state and sync
 | ||||
| 	 * bus->mapped_pcmcia_seg with hardware state. */ | ||||
| 	ssb_pcmcia_switch_segment(bus, 0); | ||||
| 	/* Init the COR register. */ | ||||
| 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 	/* Some cards also need this register to get poked. */ | ||||
| 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||||
| 	if (err) | ||||
| 		return err; | ||||
| 
 | ||||
| 	return 0; | ||||
| } | ||||
| 
 | ||||
| void ssb_pcmcia_exit(struct ssb_bus *bus) | ||||
| { | ||||
| 	if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||||
| @ -699,16 +722,7 @@ int ssb_pcmcia_init(struct ssb_bus *bus) | ||||
| 	if (bus->bustype != SSB_BUSTYPE_PCMCIA) | ||||
| 		return 0; | ||||
| 
 | ||||
| 	/* Switch segment to a known state and sync
 | ||||
| 	 * bus->mapped_pcmcia_seg with hardware state. */ | ||||
| 	ssb_pcmcia_switch_segment(bus, 0); | ||||
| 
 | ||||
| 	/* Init the COR register. */ | ||||
| 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 	/* Some cards also need this register to get poked. */ | ||||
| 	err = ssb_pcmcia_cor_setup(bus, CISREG_COR + 0x80); | ||||
| 	err = ssb_pcmcia_hardware_setup(bus); | ||||
| 	if (err) | ||||
| 		goto error; | ||||
| 
 | ||||
|  | ||||
| @ -81,6 +81,7 @@ extern int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | ||||
| 				     u8 seg); | ||||
| extern int ssb_pcmcia_get_invariants(struct ssb_bus *bus, | ||||
| 				     struct ssb_init_invariants *iv); | ||||
| extern int ssb_pcmcia_hardware_setup(struct ssb_bus *bus); | ||||
| extern void ssb_pcmcia_exit(struct ssb_bus *bus); | ||||
| extern int ssb_pcmcia_init(struct ssb_bus *bus); | ||||
| extern const struct ssb_bus_ops ssb_pcmcia_ops; | ||||
| @ -100,6 +101,10 @@ static inline int ssb_pcmcia_switch_segment(struct ssb_bus *bus, | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline int ssb_pcmcia_hardware_setup(struct ssb_bus *bus) | ||||
| { | ||||
| 	return 0; | ||||
| } | ||||
| static inline void ssb_pcmcia_exit(struct ssb_bus *bus) | ||||
| { | ||||
| } | ||||
|  | ||||
| @ -260,9 +260,6 @@ struct ssb_bus { | ||||
| 	struct ssb_device devices[SSB_MAX_NR_CORES]; | ||||
| 	u8 nr_devices; | ||||
| 
 | ||||
| 	/* Reference count. Number of suspended devices. */ | ||||
| 	u8 suspend_cnt; | ||||
| 
 | ||||
| 	/* Software ID number for this bus. */ | ||||
| 	unsigned int busnumber; | ||||
| 
 | ||||
| @ -334,6 +331,13 @@ extern int ssb_bus_pcmciabus_register(struct ssb_bus *bus, | ||||
| 
 | ||||
| extern void ssb_bus_unregister(struct ssb_bus *bus); | ||||
| 
 | ||||
| /* Suspend a SSB bus.
 | ||||
|  * Call this from the parent bus suspend routine. */ | ||||
| extern int ssb_bus_suspend(struct ssb_bus *bus); | ||||
| /* Resume a SSB bus.
 | ||||
|  * Call this from the parent bus resume routine. */ | ||||
| extern int ssb_bus_resume(struct ssb_bus *bus); | ||||
| 
 | ||||
| extern u32 ssb_clockspeed(struct ssb_bus *bus); | ||||
| 
 | ||||
| /* Is the device enabled in hardware? */ | ||||
|  | ||||
| @ -367,8 +367,7 @@ static inline bool ssb_chipco_available(struct ssb_chipcommon *cc) | ||||
| 
 | ||||
| extern void ssb_chipcommon_init(struct ssb_chipcommon *cc); | ||||
| 
 | ||||
| #include <linux/pm.h> | ||||
| extern void ssb_chipco_suspend(struct ssb_chipcommon *cc, pm_message_t state); | ||||
| extern void ssb_chipco_suspend(struct ssb_chipcommon *cc); | ||||
| extern void ssb_chipco_resume(struct ssb_chipcommon *cc); | ||||
| 
 | ||||
| extern void ssb_chipco_get_clockcpu(struct ssb_chipcommon *cc, | ||||
|  | ||||
		Loading…
	
		Reference in New Issue
	
	Block a user