Skip to content

Commit

Permalink
ssb: Turn suspend/resume upside down
Browse files Browse the repository at this point in the history
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>
  • Loading branch information
Michael Buesch authored and John W. Linville committed Apr 8, 2008
1 parent 5100d5a commit 8fe2b65
Show file tree
Hide file tree
Showing 8 changed files with 88 additions and 67 deletions.
10 changes: 6 additions & 4 deletions drivers/net/wireless/b43/pcmcia.c
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
2 changes: 1 addition & 1 deletion drivers/ssb/driver_chipcommon.c
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down
81 changes: 34 additions & 47 deletions drivers/ssb/main.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -160,27 +137,10 @@ static int ssb_device_resume(struct device *dev)
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) {
Expand All @@ -190,17 +150,44 @@ static int ssb_device_suspend(struct device *dev, pm_message_t state)
if (err)
goto out;
}
out:
return err;
}

int ssb_bus_resume(struct ssb_bus *bus)
{
int err;

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);
/* 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);

out:
return err;
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)
Expand Down
10 changes: 10 additions & 0 deletions drivers/ssb/pcihost_wrapper.c
Original file line number Diff line number Diff line change
Expand Up @@ -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));
Expand All @@ -27,13 +33,17 @@ 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);
err = pci_enable_device(dev);
if (err)
return err;
pci_restore_state(dev);
err = ssb_bus_resume(ssb);
if (err)
return err;

return 0;
}
Expand Down
34 changes: 24 additions & 10 deletions drivers/ssb/pcmcia.c
Original file line number Diff line number Diff line change
Expand Up @@ -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)
Expand All @@ -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;

Expand Down
5 changes: 5 additions & 0 deletions drivers/ssb/ssb_private.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand All @@ -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)
{
}
Expand Down
10 changes: 7 additions & 3 deletions include/linux/ssb/ssb.h
Original file line number Diff line number Diff line change
Expand Up @@ -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;

Expand Down Expand Up @@ -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? */
Expand Down
3 changes: 1 addition & 2 deletions include/linux/ssb/ssb_driver_chipcommon.h
Original file line number Diff line number Diff line change
Expand Up @@ -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,
Expand Down

0 comments on commit 8fe2b65

Please sign in to comment.