Skip to content

Commit

Permalink
pcmcia: use dev_pm_ops for class pcmcia_socket_class
Browse files Browse the repository at this point in the history
Instead of requiring PCMCIA socket drivers to call various functions
during their (bus) resume and suspend functions, register an own
dev_pm_ops for this class. This fixes several suspend/resume bugs
seen on db1xxx-ss, and probably on some other socket drivers, too.

With regard to the asymmetry with only _noirq suspend, but split up
resume, please see bug 14334 and commit 9905d1b .

Signed-off-by: Dominik Brodowski <linux@dominikbrodowski.net>
  • Loading branch information
Dominik Brodowski committed Mar 24, 2010
1 parent e7176a3 commit d7646f7
Show file tree
Hide file tree
Showing 19 changed files with 66 additions and 288 deletions.
2 changes: 0 additions & 2 deletions drivers/pcmcia/at91_cf.c
Original file line number Diff line number Diff line change
Expand Up @@ -361,7 +361,6 @@ static int at91_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
struct at91_cf_socket *cf = platform_get_drvdata(pdev);
struct at91_cf_data *board = cf->board;

pcmcia_socket_dev_suspend(&pdev->dev);
if (device_may_wakeup(&pdev->dev)) {
enable_irq_wake(board->det_pin);
if (board->irq_pin)
Expand All @@ -381,7 +380,6 @@ static int at91_cf_resume(struct platform_device *pdev)
disable_irq_wake(board->irq_pin);
}

pcmcia_socket_dev_resume(&pdev->dev);
return 0;
}

Expand Down
13 changes: 0 additions & 13 deletions drivers/pcmcia/au1000_generic.c
Original file line number Diff line number Diff line change
Expand Up @@ -510,26 +510,13 @@ static int au1x00_drv_pcmcia_probe(struct platform_device *dev)
return ret;
}

static int au1x00_drv_pcmcia_suspend(struct platform_device *dev,
pm_message_t state)
{
return pcmcia_socket_dev_suspend(&dev->dev);
}

static int au1x00_drv_pcmcia_resume(struct platform_device *dev)
{
return pcmcia_socket_dev_resume(&dev->dev);
}

static struct platform_driver au1x00_pcmcia_driver = {
.driver = {
.name = "au1x00-pcmcia",
.owner = THIS_MODULE,
},
.probe = au1x00_drv_pcmcia_probe,
.remove = au1x00_drv_pcmcia_remove,
.suspend = au1x00_drv_pcmcia_suspend,
.resume = au1x00_drv_pcmcia_resume,
};


Expand Down
12 changes: 0 additions & 12 deletions drivers/pcmcia/bfin_cf_pcmcia.c
Original file line number Diff line number Diff line change
Expand Up @@ -300,25 +300,13 @@ static int __devexit bfin_cf_remove(struct platform_device *pdev)
return 0;
}

static int bfin_cf_suspend(struct platform_device *pdev, pm_message_t mesg)
{
return pcmcia_socket_dev_suspend(&pdev->dev);
}

static int bfin_cf_resume(struct platform_device *pdev)
{
return pcmcia_socket_dev_resume(&pdev->dev);
}

static struct platform_driver bfin_cf_driver = {
.driver = {
.name = (char *)driver_name,
.owner = THIS_MODULE,
},
.probe = bfin_cf_probe,
.remove = __devexit_p(bfin_cf_remove),
.suspend = bfin_cf_suspend,
.resume = bfin_cf_resume,
};

static int __init bfin_cf_init(void)
Expand Down
124 changes: 63 additions & 61 deletions drivers/pcmcia/cs.c
Original file line number Diff line number Diff line change
Expand Up @@ -76,65 +76,6 @@ DECLARE_RWSEM(pcmcia_socket_list_rwsem);
EXPORT_SYMBOL(pcmcia_socket_list_rwsem);


/*
* Low-level PCMCIA socket drivers need to register with the PCCard
* core using pcmcia_register_socket.
*
* socket drivers are expected to use the following callbacks in their
* .drv struct:
* - pcmcia_socket_dev_suspend
* - pcmcia_socket_dev_resume
* These functions check for the appropriate struct pcmcia_soket arrays,
* and pass them to the low-level functions pcmcia_{suspend,resume}_socket
*/
static int socket_early_resume(struct pcmcia_socket *skt);
static int socket_late_resume(struct pcmcia_socket *skt);
static int socket_resume(struct pcmcia_socket *skt);
static int socket_suspend(struct pcmcia_socket *skt);

static void pcmcia_socket_dev_run(struct device *dev,
int (*cb)(struct pcmcia_socket *))
{
struct pcmcia_socket *socket;

down_read(&pcmcia_socket_list_rwsem);
list_for_each_entry(socket, &pcmcia_socket_list, socket_list) {
if (socket->dev.parent != dev)
continue;
mutex_lock(&socket->skt_mutex);
cb(socket);
mutex_unlock(&socket->skt_mutex);
}
up_read(&pcmcia_socket_list_rwsem);
}

int pcmcia_socket_dev_suspend(struct device *dev)
{
pcmcia_socket_dev_run(dev, socket_suspend);
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_suspend);

void pcmcia_socket_dev_early_resume(struct device *dev)
{
pcmcia_socket_dev_run(dev, socket_early_resume);
}
EXPORT_SYMBOL(pcmcia_socket_dev_early_resume);

void pcmcia_socket_dev_late_resume(struct device *dev)
{
pcmcia_socket_dev_run(dev, socket_late_resume);
}
EXPORT_SYMBOL(pcmcia_socket_dev_late_resume);

int pcmcia_socket_dev_resume(struct device *dev)
{
pcmcia_socket_dev_run(dev, socket_resume);
return 0;
}
EXPORT_SYMBOL(pcmcia_socket_dev_resume);


struct pcmcia_socket *pcmcia_get_socket(struct pcmcia_socket *skt)
{
struct device *dev = get_device(&skt->dev);
Expand Down Expand Up @@ -578,12 +519,18 @@ static int socket_early_resume(struct pcmcia_socket *skt)

static int socket_late_resume(struct pcmcia_socket *skt)
{
int ret;

mutex_lock(&skt->ops_mutex);
skt->state &= ~SOCKET_SUSPEND;
mutex_unlock(&skt->ops_mutex);

if (!(skt->state & SOCKET_PRESENT))
return socket_insert(skt);
if (!(skt->state & SOCKET_PRESENT)) {
ret = socket_insert(skt);
if (ret == -ENODEV)
ret = 0;
return ret;
}

if (skt->resume_status) {
socket_shutdown(skt);
Expand Down Expand Up @@ -919,11 +866,66 @@ static void pcmcia_release_socket_class(struct class *data)
}


#ifdef CONFIG_PM

static int __pcmcia_pm_op(struct device *dev,
int (*callback) (struct pcmcia_socket *skt))
{
struct pcmcia_socket *s = container_of(dev, struct pcmcia_socket, dev);
int ret;

mutex_lock(&s->skt_mutex);
ret = callback(s);
mutex_unlock(&s->skt_mutex);

return ret;
}

static int pcmcia_socket_dev_suspend_noirq(struct device *dev)
{
return __pcmcia_pm_op(dev, socket_suspend);
}

static int pcmcia_socket_dev_resume_noirq(struct device *dev)
{
return __pcmcia_pm_op(dev, socket_early_resume);
}

static int pcmcia_socket_dev_resume(struct device *dev)
{
return __pcmcia_pm_op(dev, socket_late_resume);
}

static const struct dev_pm_ops pcmcia_socket_pm_ops = {
/* dev_resume may be called with IRQs enabled */
SET_SYSTEM_SLEEP_PM_OPS(NULL,
pcmcia_socket_dev_resume)

/* late suspend must be called with IRQs disabled */
.suspend_noirq = pcmcia_socket_dev_suspend_noirq,
.freeze_noirq = pcmcia_socket_dev_suspend_noirq,
.poweroff_noirq = pcmcia_socket_dev_suspend_noirq,

/* early resume must be called with IRQs disabled */
.resume_noirq = pcmcia_socket_dev_resume_noirq,
.thaw_noirq = pcmcia_socket_dev_resume_noirq,
.restore_noirq = pcmcia_socket_dev_resume_noirq,
};

#define PCMCIA_SOCKET_CLASS_PM_OPS (&pcmcia_socket_pm_ops)

#else /* CONFIG_PM */

#define PCMCIA_SOCKET_CLASS_PM_OPS NULL

#endif /* CONFIG_PM */

struct class pcmcia_socket_class = {
.name = "pcmcia_socket",
.dev_uevent = pcmcia_socket_uevent,
.dev_release = pcmcia_release_socket,
.class_release = pcmcia_release_socket_class,
.pm = PCMCIA_SOCKET_CLASS_PM_OPS,
};
EXPORT_SYMBOL(pcmcia_socket_class);

Expand Down
27 changes: 0 additions & 27 deletions drivers/pcmcia/db1xxx_ss.c
Original file line number Diff line number Diff line change
Expand Up @@ -558,37 +558,10 @@ static int __devexit db1x_pcmcia_socket_remove(struct platform_device *pdev)
return 0;
}

#ifdef CONFIG_PM
static int db1x_pcmcia_suspend(struct device *dev)
{
return pcmcia_socket_dev_suspend(dev);
}

static int db1x_pcmcia_resume(struct device *dev)
{
return pcmcia_socket_dev_resume(dev);
}

static struct dev_pm_ops db1x_pcmcia_pmops = {
.resume = db1x_pcmcia_resume,
.suspend = db1x_pcmcia_suspend,
.thaw = db1x_pcmcia_resume,
.freeze = db1x_pcmcia_suspend,
};

#define DB1XXX_SS_PMOPS &db1x_pcmcia_pmops

#else

#define DB1XXX_SS_PMOPS NULL

#endif

static struct platform_driver db1x_pcmcia_socket_driver = {
.driver = {
.name = "db1xxx_pcmcia",
.owner = THIS_MODULE,
.pm = DB1XXX_SS_PMOPS
},
.probe = db1x_pcmcia_socket_probe,
.remove = __devexit_p(db1x_pcmcia_socket_remove),
Expand Down
16 changes: 0 additions & 16 deletions drivers/pcmcia/i82092.c
Original file line number Diff line number Diff line change
Expand Up @@ -39,27 +39,11 @@ static struct pci_device_id i82092aa_pci_ids[] = {
};
MODULE_DEVICE_TABLE(pci, i82092aa_pci_ids);

#ifdef CONFIG_PM
static int i82092aa_socket_suspend (struct pci_dev *dev, pm_message_t state)
{
return pcmcia_socket_dev_suspend(&dev->dev);
}

static int i82092aa_socket_resume (struct pci_dev *dev)
{
return pcmcia_socket_dev_resume(&dev->dev);
}
#endif

static struct pci_driver i82092aa_pci_driver = {
.name = "i82092aa",
.id_table = i82092aa_pci_ids,
.probe = i82092aa_pci_probe,
.remove = __devexit_p(i82092aa_pci_remove),
#ifdef CONFIG_PM
.suspend = i82092aa_socket_suspend,
.resume = i82092aa_socket_resume,
#endif
};


Expand Down
11 changes: 0 additions & 11 deletions drivers/pcmcia/i82365.c
Original file line number Diff line number Diff line change
Expand Up @@ -1223,16 +1223,7 @@ static int pcic_init(struct pcmcia_socket *s)
return 0;
}

static int i82365_drv_pcmcia_suspend(struct platform_device *dev,
pm_message_t state)
{
return pcmcia_socket_dev_suspend(&dev->dev);
}

static int i82365_drv_pcmcia_resume(struct platform_device *dev)
{
return pcmcia_socket_dev_resume(&dev->dev);
}
static struct pccard_operations pcic_operations = {
.init = pcic_init,
.get_status = pcic_get_status,
Expand All @@ -1248,8 +1239,6 @@ static struct platform_driver i82365_driver = {
.name = "i82365",
.owner = THIS_MODULE,
},
.suspend = i82365_drv_pcmcia_suspend,
.resume = i82365_drv_pcmcia_resume,
};

static struct platform_device *i82365_device;
Expand Down
11 changes: 0 additions & 11 deletions drivers/pcmcia/m32r_cfc.c
Original file line number Diff line number Diff line change
Expand Up @@ -685,25 +685,14 @@ static struct pccard_operations pcc_operations = {
.set_mem_map = pcc_set_mem_map,
};

static int cfc_drv_pcmcia_suspend(struct platform_device *dev,
pm_message_t state)
{
return pcmcia_socket_dev_suspend(&dev->dev);
}

static int cfc_drv_pcmcia_resume(struct platform_device *dev)
{
return pcmcia_socket_dev_resume(&dev->dev);
}
/*====================================================================*/

static struct platform_driver pcc_driver = {
.driver = {
.name = "cfc",
.owner = THIS_MODULE,
},
.suspend = cfc_drv_pcmcia_suspend,
.resume = cfc_drv_pcmcia_resume,
};

static struct platform_device pcc_device = {
Expand Down
12 changes: 0 additions & 12 deletions drivers/pcmcia/m32r_pcc.c
Original file line number Diff line number Diff line change
Expand Up @@ -663,25 +663,13 @@ static struct pccard_operations pcc_operations = {
.set_mem_map = pcc_set_mem_map,
};

static int pcc_drv_pcmcia_suspend(struct platform_device *dev,
pm_message_t state)
{
return pcmcia_socket_dev_suspend(&dev->dev);
}

static int pcc_drv_pcmcia_resume(struct platform_device *dev)
{
return pcmcia_socket_dev_resume(&dev->dev);
}
/*====================================================================*/

static struct platform_driver pcc_driver = {
.driver = {
.name = "pcc",
.owner = THIS_MODULE,
},
.suspend = pcc_drv_pcmcia_suspend,
.resume = pcc_drv_pcmcia_resume,
};

static struct platform_device pcc_device = {
Expand Down
17 changes: 0 additions & 17 deletions drivers/pcmcia/m8xx_pcmcia.c
Original file line number Diff line number Diff line change
Expand Up @@ -1288,21 +1288,6 @@ static int m8xx_remove(struct of_device *ofdev)
return 0;
}

#ifdef CONFIG_PM
static int m8xx_suspend(struct platform_device *pdev, pm_message_t state)
{
return pcmcia_socket_dev_suspend(&pdev->dev);
}

static int m8xx_resume(struct platform_device *pdev)
{
return pcmcia_socket_dev_resume(&pdev->dev);
}
#else
#define m8xx_suspend NULL
#define m8xx_resume NULL
#endif

static const struct of_device_id m8xx_pcmcia_match[] = {
{
.type = "pcmcia",
Expand All @@ -1318,8 +1303,6 @@ static struct of_platform_driver m8xx_pcmcia_driver = {
.match_table = m8xx_pcmcia_match,
.probe = m8xx_probe,
.remove = m8xx_remove,
.suspend = m8xx_suspend,
.resume = m8xx_resume,
};

static int __init m8xx_init(void)
Expand Down
Loading

0 comments on commit d7646f7

Please sign in to comment.