3c59x: Rework suspend and resume

As noticed by Alan Stern, there is still one issue with the driver:
we disable PCI IRQ on suspend, but other devices on the same IRQ
line might still need the IRQ enabled to suspend properly.

Nowadays, PCI core handles all power management work by itself, with
one condition though: if we use dev_pm_ops. So, rework the driver to
only quiesce 3c59x internal logic on suspend, while PCI core will
manage PCI device power state with IRQs disabled.

Suggested-by: Rafael J. Wysocki <rjw@sisk.pl>
Suggested-by: Alan Stern <stern@rowland.harvard.edu>
Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com>
Acked-by: Rafael J. Wysocki <rjw@sisk.pl>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Anton Vorontsov 2009-09-30 20:11:11 -07:00 committed by David S. Miller
parent a55c0a0ed4
commit 7bfc4ab562
1 changed files with 38 additions and 39 deletions

View File

@ -805,52 +805,54 @@ static void poll_vortex(struct net_device *dev)
#ifdef CONFIG_PM #ifdef CONFIG_PM
static int vortex_suspend(struct pci_dev *pdev, pm_message_t state) static int vortex_suspend(struct device *dev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct pci_dev *pdev = to_pci_dev(dev);
struct net_device *ndev = pci_get_drvdata(pdev);
if (!ndev || !netif_running(ndev))
return 0;
netif_device_detach(ndev);
vortex_down(ndev, 1);
if (dev && netdev_priv(dev)) {
if (netif_running(dev)) {
netif_device_detach(dev);
vortex_down(dev, 1);
disable_irq(dev->irq);
}
pci_save_state(pdev);
pci_enable_wake(pdev, pci_choose_state(pdev, state), 0);
pci_disable_device(pdev);
pci_set_power_state(pdev, pci_choose_state(pdev, state));
}
return 0; return 0;
} }
static int vortex_resume(struct pci_dev *pdev) static int vortex_resume(struct device *dev)
{ {
struct net_device *dev = pci_get_drvdata(pdev); struct pci_dev *pdev = to_pci_dev(dev);
struct vortex_private *vp = netdev_priv(dev); struct net_device *ndev = pci_get_drvdata(pdev);
int err; int err;
if (dev && vp) { if (!ndev || !netif_running(ndev))
pci_set_power_state(pdev, PCI_D0); return 0;
pci_restore_state(pdev);
err = pci_enable_device(pdev); err = vortex_up(ndev);
if (err) { if (err)
pr_warning("%s: Could not enable device\n", return err;
dev->name);
return err; netif_device_attach(ndev);
}
pci_set_master(pdev);
if (netif_running(dev)) {
err = vortex_up(dev);
if (err)
return err;
enable_irq(dev->irq);
netif_device_attach(dev);
}
}
return 0; return 0;
} }
#endif /* CONFIG_PM */ static struct dev_pm_ops vortex_pm_ops = {
.suspend = vortex_suspend,
.resume = vortex_resume,
.freeze = vortex_suspend,
.thaw = vortex_resume,
.poweroff = vortex_suspend,
.restore = vortex_resume,
};
#define VORTEX_PM_OPS (&vortex_pm_ops)
#else /* !CONFIG_PM */
#define VORTEX_PM_OPS NULL
#endif /* !CONFIG_PM */
#ifdef CONFIG_EISA #ifdef CONFIG_EISA
static struct eisa_device_id vortex_eisa_ids[] = { static struct eisa_device_id vortex_eisa_ids[] = {
@ -3199,10 +3201,7 @@ static struct pci_driver vortex_driver = {
.probe = vortex_init_one, .probe = vortex_init_one,
.remove = __devexit_p(vortex_remove_one), .remove = __devexit_p(vortex_remove_one),
.id_table = vortex_pci_tbl, .id_table = vortex_pci_tbl,
#ifdef CONFIG_PM .driver.pm = VORTEX_PM_OPS,
.suspend = vortex_suspend,
.resume = vortex_resume,
#endif
}; };