tlan: add suspend/resume support

Add suspend/resume support to tlan driver. This allows not unloading the
driver over suspend/resume.

Also, start (or now, wake) the queue after resetting the adapter --- not the
other way around.

Signed-off-by: Sakari Ailus <sakari.ailus@iki.fi>
Signed-off-by: David S. Miller <davem@davemloft.net>
This commit is contained in:
Sakari Ailus 2011-01-21 10:59:31 +00:00 committed by David S. Miller
parent c659c38b27
commit fa6d5d4f2b

View file

@ -168,6 +168,7 @@
*
* v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway.
* v1.16 Jan 6 2011 - Make checkpatch.pl happy.
* v1.17 Jan 6 2011 - Add suspend/resume support.
*
******************************************************************************/
@ -219,7 +220,7 @@ module_param(debug, int, 0);
MODULE_PARM_DESC(debug, "ThunderLAN debug mask");
static const char tlan_signature[] = "TLAN";
static const char tlan_banner[] = "ThunderLAN driver v1.16\n";
static const char tlan_banner[] = "ThunderLAN driver v1.17\n";
static int tlan_have_pci;
static int tlan_have_eisa;
@ -462,11 +463,79 @@ static void __devexit tlan_remove_one(struct pci_dev *pdev)
pci_set_drvdata(pdev, NULL);
}
static void tlan_start(struct net_device *dev)
{
tlan_reset_lists(dev);
/* NOTE: It might not be necessary to read the stats before a
reset if you don't care what the values are.
*/
tlan_read_and_clear_stats(dev, TLAN_IGNORE);
tlan_reset_adapter(dev);
netif_wake_queue(dev);
}
static void tlan_stop(struct net_device *dev)
{
struct tlan_priv *priv = netdev_priv(dev);
tlan_read_and_clear_stats(dev, TLAN_RECORD);
outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD);
/* Reset and power down phy */
tlan_reset_adapter(dev);
if (priv->timer.function != NULL) {
del_timer_sync(&priv->timer);
priv->timer.function = NULL;
}
}
#ifdef CONFIG_PM
static int tlan_suspend(struct pci_dev *pdev, pm_message_t state)
{
struct net_device *dev = pci_get_drvdata(pdev);
if (netif_running(dev))
tlan_stop(dev);
netif_device_detach(dev);
pci_save_state(pdev);
pci_disable_device(pdev);
pci_wake_from_d3(pdev, false);
pci_set_power_state(pdev, PCI_D3hot);
return 0;
}
static int tlan_resume(struct pci_dev *pdev)
{
struct net_device *dev = pci_get_drvdata(pdev);
pci_set_power_state(pdev, PCI_D0);
pci_restore_state(pdev);
pci_enable_wake(pdev, 0, 0);
netif_device_attach(dev);
if (netif_running(dev))
tlan_start(dev);
return 0;
}
#else /* CONFIG_PM */
#define tlan_suspend NULL
#define tlan_resume NULL
#endif /* CONFIG_PM */
static struct pci_driver tlan_driver = {
.name = "tlan",
.id_table = tlan_pci_tbl,
.probe = tlan_init_one,
.remove = __devexit_p(tlan_remove_one),
.suspend = tlan_suspend,
.resume = tlan_resume,
};
static int __init tlan_probe(void)
@ -965,14 +1034,8 @@ static int tlan_open(struct net_device *dev)
}
init_timer(&priv->timer);
netif_start_queue(dev);
/* NOTE: It might not be necessary to read the stats before a
reset if you don't care what the values are.
*/
tlan_reset_lists(dev);
tlan_read_and_clear_stats(dev, TLAN_IGNORE);
tlan_reset_adapter(dev);
tlan_start(dev);
TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n",
dev->name, priv->tlan_rev);
@ -1243,15 +1306,8 @@ static int tlan_close(struct net_device *dev)
{
struct tlan_priv *priv = netdev_priv(dev);
netif_stop_queue(dev);
priv->neg_be_verbose = 0;
tlan_read_and_clear_stats(dev, TLAN_RECORD);
outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD);
if (priv->timer.function != NULL) {
del_timer_sync(&priv->timer);
priv->timer.function = NULL;
}
tlan_stop(dev);
free_irq(dev->irq, dev);
tlan_free_lists(dev);