diff options
author | Sakari Ailus <sakari.ailus@iki.fi> | 2011-01-21 05:59:31 -0500 |
---|---|---|
committer | David S. Miller <davem@davemloft.net> | 2011-01-24 18:07:06 -0500 |
commit | fa6d5d4f2b0df1e9b613b7b5926805b8a4306d44 (patch) | |
tree | 607fd5c8087821d0d140ad66707c7598c7c40de6 /drivers/net/tlan.c | |
parent | c659c38b2796578638548b77ef626d93609ec8ac (diff) |
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>
Diffstat (limited to 'drivers/net/tlan.c')
-rw-r--r-- | drivers/net/tlan.c | 88 |
1 files changed, 72 insertions, 16 deletions
diff --git a/drivers/net/tlan.c b/drivers/net/tlan.c index 57380b1b3b60..0678e7e71f19 100644 --- a/drivers/net/tlan.c +++ b/drivers/net/tlan.c | |||
@@ -168,6 +168,7 @@ | |||
168 | * | 168 | * |
169 | * v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway. | 169 | * v1.15a Dec 15 2008 - Remove bbuf support, it doesn't work anyway. |
170 | * v1.16 Jan 6 2011 - Make checkpatch.pl happy. | 170 | * v1.16 Jan 6 2011 - Make checkpatch.pl happy. |
171 | * v1.17 Jan 6 2011 - Add suspend/resume support. | ||
171 | * | 172 | * |
172 | ******************************************************************************/ | 173 | ******************************************************************************/ |
173 | 174 | ||
@@ -219,7 +220,7 @@ module_param(debug, int, 0); | |||
219 | MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); | 220 | MODULE_PARM_DESC(debug, "ThunderLAN debug mask"); |
220 | 221 | ||
221 | static const char tlan_signature[] = "TLAN"; | 222 | static const char tlan_signature[] = "TLAN"; |
222 | static const char tlan_banner[] = "ThunderLAN driver v1.16\n"; | 223 | static const char tlan_banner[] = "ThunderLAN driver v1.17\n"; |
223 | static int tlan_have_pci; | 224 | static int tlan_have_pci; |
224 | static int tlan_have_eisa; | 225 | static int tlan_have_eisa; |
225 | 226 | ||
@@ -462,11 +463,79 @@ static void __devexit tlan_remove_one(struct pci_dev *pdev) | |||
462 | pci_set_drvdata(pdev, NULL); | 463 | pci_set_drvdata(pdev, NULL); |
463 | } | 464 | } |
464 | 465 | ||
466 | static void tlan_start(struct net_device *dev) | ||
467 | { | ||
468 | tlan_reset_lists(dev); | ||
469 | /* NOTE: It might not be necessary to read the stats before a | ||
470 | reset if you don't care what the values are. | ||
471 | */ | ||
472 | tlan_read_and_clear_stats(dev, TLAN_IGNORE); | ||
473 | tlan_reset_adapter(dev); | ||
474 | netif_wake_queue(dev); | ||
475 | } | ||
476 | |||
477 | static void tlan_stop(struct net_device *dev) | ||
478 | { | ||
479 | struct tlan_priv *priv = netdev_priv(dev); | ||
480 | |||
481 | tlan_read_and_clear_stats(dev, TLAN_RECORD); | ||
482 | outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); | ||
483 | /* Reset and power down phy */ | ||
484 | tlan_reset_adapter(dev); | ||
485 | if (priv->timer.function != NULL) { | ||
486 | del_timer_sync(&priv->timer); | ||
487 | priv->timer.function = NULL; | ||
488 | } | ||
489 | } | ||
490 | |||
491 | #ifdef CONFIG_PM | ||
492 | |||
493 | static int tlan_suspend(struct pci_dev *pdev, pm_message_t state) | ||
494 | { | ||
495 | struct net_device *dev = pci_get_drvdata(pdev); | ||
496 | |||
497 | if (netif_running(dev)) | ||
498 | tlan_stop(dev); | ||
499 | |||
500 | netif_device_detach(dev); | ||
501 | pci_save_state(pdev); | ||
502 | pci_disable_device(pdev); | ||
503 | pci_wake_from_d3(pdev, false); | ||
504 | pci_set_power_state(pdev, PCI_D3hot); | ||
505 | |||
506 | return 0; | ||
507 | } | ||
508 | |||
509 | static int tlan_resume(struct pci_dev *pdev) | ||
510 | { | ||
511 | struct net_device *dev = pci_get_drvdata(pdev); | ||
512 | |||
513 | pci_set_power_state(pdev, PCI_D0); | ||
514 | pci_restore_state(pdev); | ||
515 | pci_enable_wake(pdev, 0, 0); | ||
516 | netif_device_attach(dev); | ||
517 | |||
518 | if (netif_running(dev)) | ||
519 | tlan_start(dev); | ||
520 | |||
521 | return 0; | ||
522 | } | ||
523 | |||
524 | #else /* CONFIG_PM */ | ||
525 | |||
526 | #define tlan_suspend NULL | ||
527 | #define tlan_resume NULL | ||
528 | |||
529 | #endif /* CONFIG_PM */ | ||
530 | |||
531 | |||
465 | static struct pci_driver tlan_driver = { | 532 | static struct pci_driver tlan_driver = { |
466 | .name = "tlan", | 533 | .name = "tlan", |
467 | .id_table = tlan_pci_tbl, | 534 | .id_table = tlan_pci_tbl, |
468 | .probe = tlan_init_one, | 535 | .probe = tlan_init_one, |
469 | .remove = __devexit_p(tlan_remove_one), | 536 | .remove = __devexit_p(tlan_remove_one), |
537 | .suspend = tlan_suspend, | ||
538 | .resume = tlan_resume, | ||
470 | }; | 539 | }; |
471 | 540 | ||
472 | static int __init tlan_probe(void) | 541 | static int __init tlan_probe(void) |
@@ -965,14 +1034,8 @@ static int tlan_open(struct net_device *dev) | |||
965 | } | 1034 | } |
966 | 1035 | ||
967 | init_timer(&priv->timer); | 1036 | init_timer(&priv->timer); |
968 | netif_start_queue(dev); | ||
969 | 1037 | ||
970 | /* NOTE: It might not be necessary to read the stats before a | 1038 | tlan_start(dev); |
971 | reset if you don't care what the values are. | ||
972 | */ | ||
973 | tlan_reset_lists(dev); | ||
974 | tlan_read_and_clear_stats(dev, TLAN_IGNORE); | ||
975 | tlan_reset_adapter(dev); | ||
976 | 1039 | ||
977 | TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", | 1040 | TLAN_DBG(TLAN_DEBUG_GNRL, "%s: Opened. TLAN Chip Rev: %x\n", |
978 | dev->name, priv->tlan_rev); | 1041 | dev->name, priv->tlan_rev); |
@@ -1243,15 +1306,8 @@ static int tlan_close(struct net_device *dev) | |||
1243 | { | 1306 | { |
1244 | struct tlan_priv *priv = netdev_priv(dev); | 1307 | struct tlan_priv *priv = netdev_priv(dev); |
1245 | 1308 | ||
1246 | netif_stop_queue(dev); | ||
1247 | priv->neg_be_verbose = 0; | 1309 | priv->neg_be_verbose = 0; |
1248 | 1310 | tlan_stop(dev); | |
1249 | tlan_read_and_clear_stats(dev, TLAN_RECORD); | ||
1250 | outl(TLAN_HC_AD_RST, dev->base_addr + TLAN_HOST_CMD); | ||
1251 | if (priv->timer.function != NULL) { | ||
1252 | del_timer_sync(&priv->timer); | ||
1253 | priv->timer.function = NULL; | ||
1254 | } | ||
1255 | 1311 | ||
1256 | free_irq(dev->irq, dev); | 1312 | free_irq(dev->irq, dev); |
1257 | tlan_free_lists(dev); | 1313 | tlan_free_lists(dev); |