mirror of
https://mirrors.bfsu.edu.cn/git/linux.git
synced 2024-11-11 12:28:41 +08:00
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:
parent
c659c38b27
commit
fa6d5d4f2b
@ -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);
|
||||
|
Loading…
Reference in New Issue
Block a user