aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net
diff options
context:
space:
mode:
authorAnton Vorontsov <avorontsov@ru.mvista.com>2009-08-27 03:35:57 -0400
committerDavid S. Miller <davem@davemloft.net>2009-08-31 00:51:47 -0400
commit2394905f67aeec5f9452f2881cbeb2b42009de0e (patch)
tree799de0b229027408b0f894cb9f50e36f4707f3d7 /drivers/net
parentbf5aec2e79418adb42f1457152b427fd3d6316d9 (diff)
ucc_geth: Implement suspend/resume and Wake-On-LAN support
This patch implements suspend/resume and WOL support for UCC Ethernet driver. We support two wake up events: wake on PHY/link changes and wake on magic packet. In some CPUs (like MPC8569) QE shuts down during sleep, so magic packet detection is unusable, and also on resume we should fully reinitialize UCC structures. Signed-off-by: Anton Vorontsov <avorontsov@ru.mvista.com> Signed-off-by: David S. Miller <davem@davemloft.net>
Diffstat (limited to 'drivers/net')
-rw-r--r--drivers/net/ucc_geth.c85
-rw-r--r--drivers/net/ucc_geth.h1
-rw-r--r--drivers/net/ucc_geth_ethtool.c40
3 files changed, 126 insertions, 0 deletions
diff --git a/drivers/net/ucc_geth.c b/drivers/net/ucc_geth.c
index d2ca61d3dffc..7fb96f33bade 100644
--- a/drivers/net/ucc_geth.c
+++ b/drivers/net/ucc_geth.c
@@ -3497,6 +3497,10 @@ static int ucc_geth_open(struct net_device *dev)
3497 napi_enable(&ugeth->napi); 3497 napi_enable(&ugeth->napi);
3498 netif_start_queue(dev); 3498 netif_start_queue(dev);
3499 3499
3500 device_set_wakeup_capable(&dev->dev,
3501 qe_alive_during_sleep() || ugeth->phydev->irq);
3502 device_set_wakeup_enable(&dev->dev, ugeth->wol_en);
3503
3500 return err; 3504 return err;
3501 3505
3502err: 3506err:
@@ -3561,6 +3565,85 @@ static void ucc_geth_timeout(struct net_device *dev)
3561 schedule_work(&ugeth->timeout_work); 3565 schedule_work(&ugeth->timeout_work);
3562} 3566}
3563 3567
3568
3569#ifdef CONFIG_PM
3570
3571static int ucc_geth_suspend(struct of_device *ofdev, pm_message_t state)
3572{
3573 struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
3574 struct ucc_geth_private *ugeth = netdev_priv(ndev);
3575
3576 if (!netif_running(ndev))
3577 return 0;
3578
3579 napi_disable(&ugeth->napi);
3580
3581 /*
3582 * Disable the controller, otherwise we'll wakeup on any network
3583 * activity.
3584 */
3585 ugeth_disable(ugeth, COMM_DIR_RX_AND_TX);
3586
3587 if (ugeth->wol_en & WAKE_MAGIC) {
3588 setbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
3589 setbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
3590 ucc_fast_enable(ugeth->uccf, COMM_DIR_RX_AND_TX);
3591 } else if (!(ugeth->wol_en & WAKE_PHY)) {
3592 phy_stop(ugeth->phydev);
3593 }
3594
3595 return 0;
3596}
3597
3598static int ucc_geth_resume(struct of_device *ofdev)
3599{
3600 struct net_device *ndev = dev_get_drvdata(&ofdev->dev);
3601 struct ucc_geth_private *ugeth = netdev_priv(ndev);
3602 int err;
3603
3604 if (!netif_running(ndev))
3605 return 0;
3606
3607 if (qe_alive_during_sleep()) {
3608 if (ugeth->wol_en & WAKE_MAGIC) {
3609 ucc_fast_disable(ugeth->uccf, COMM_DIR_RX_AND_TX);
3610 clrbits32(&ugeth->ug_regs->maccfg2, MACCFG2_MPE);
3611 clrbits32(ugeth->uccf->p_uccm, UCC_GETH_UCCE_MPD);
3612 }
3613 ugeth_enable(ugeth, COMM_DIR_RX_AND_TX);
3614 } else {
3615 /*
3616 * Full reinitialization is required if QE shuts down
3617 * during sleep.
3618 */
3619 ucc_geth_memclean(ugeth);
3620
3621 err = ucc_geth_init_mac(ugeth);
3622 if (err) {
3623 ugeth_err("%s: Cannot initialize MAC, aborting.",
3624 ndev->name);
3625 return err;
3626 }
3627 }
3628
3629 ugeth->oldlink = 0;
3630 ugeth->oldspeed = 0;
3631 ugeth->oldduplex = -1;
3632
3633 phy_stop(ugeth->phydev);
3634 phy_start(ugeth->phydev);
3635
3636 napi_enable(&ugeth->napi);
3637 netif_start_queue(ndev);
3638
3639 return 0;
3640}
3641
3642#else
3643#define ucc_geth_suspend NULL
3644#define ucc_geth_resume NULL
3645#endif
3646
3564static phy_interface_t to_phy_interface(const char *phy_connection_type) 3647static phy_interface_t to_phy_interface(const char *phy_connection_type)
3565{ 3648{
3566 if (strcasecmp(phy_connection_type, "mii") == 0) 3649 if (strcasecmp(phy_connection_type, "mii") == 0)
@@ -3852,6 +3935,8 @@ static struct of_platform_driver ucc_geth_driver = {
3852 .match_table = ucc_geth_match, 3935 .match_table = ucc_geth_match,
3853 .probe = ucc_geth_probe, 3936 .probe = ucc_geth_probe,
3854 .remove = ucc_geth_remove, 3937 .remove = ucc_geth_remove,
3938 .suspend = ucc_geth_suspend,
3939 .resume = ucc_geth_resume,
3855}; 3940};
3856 3941
3857static int __init ucc_geth_init(void) 3942static int __init ucc_geth_init(void)
diff --git a/drivers/net/ucc_geth.h b/drivers/net/ucc_geth.h
index cfb31afc08a9..03a6ca016d5a 100644
--- a/drivers/net/ucc_geth.h
+++ b/drivers/net/ucc_geth.h
@@ -1222,6 +1222,7 @@ struct ucc_geth_private {
1222 int oldspeed; 1222 int oldspeed;
1223 int oldduplex; 1223 int oldduplex;
1224 int oldlink; 1224 int oldlink;
1225 int wol_en;
1225 1226
1226 struct device_node *node; 1227 struct device_node *node;
1227}; 1228};
diff --git a/drivers/net/ucc_geth_ethtool.c b/drivers/net/ucc_geth_ethtool.c
index 304128fa6058..7075f26e97da 100644
--- a/drivers/net/ucc_geth_ethtool.c
+++ b/drivers/net/ucc_geth_ethtool.c
@@ -359,6 +359,44 @@ uec_get_drvinfo(struct net_device *netdev,
359 drvinfo->regdump_len = uec_get_regs_len(netdev); 359 drvinfo->regdump_len = uec_get_regs_len(netdev);
360} 360}
361 361
362#ifdef CONFIG_PM
363
364static void uec_get_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
365{
366 struct ucc_geth_private *ugeth = netdev_priv(netdev);
367 struct phy_device *phydev = ugeth->phydev;
368
369 if (phydev && phydev->irq)
370 wol->supported |= WAKE_PHY;
371 if (qe_alive_during_sleep())
372 wol->supported |= WAKE_MAGIC;
373
374 wol->wolopts = ugeth->wol_en;
375}
376
377static int uec_set_wol(struct net_device *netdev, struct ethtool_wolinfo *wol)
378{
379 struct ucc_geth_private *ugeth = netdev_priv(netdev);
380 struct phy_device *phydev = ugeth->phydev;
381
382 if (wol->wolopts & ~(WAKE_PHY | WAKE_MAGIC))
383 return -EINVAL;
384 else if (wol->wolopts & WAKE_PHY && (!phydev || !phydev->irq))
385 return -EINVAL;
386 else if (wol->wolopts & WAKE_MAGIC && !qe_alive_during_sleep())
387 return -EINVAL;
388
389 ugeth->wol_en = wol->wolopts;
390 device_set_wakeup_enable(&netdev->dev, ugeth->wol_en);
391
392 return 0;
393}
394
395#else
396#define uec_get_wol NULL
397#define uec_set_wol NULL
398#endif /* CONFIG_PM */
399
362static const struct ethtool_ops uec_ethtool_ops = { 400static const struct ethtool_ops uec_ethtool_ops = {
363 .get_settings = uec_get_settings, 401 .get_settings = uec_get_settings,
364 .set_settings = uec_set_settings, 402 .set_settings = uec_set_settings,
@@ -377,6 +415,8 @@ static const struct ethtool_ops uec_ethtool_ops = {
377 .get_sset_count = uec_get_sset_count, 415 .get_sset_count = uec_get_sset_count,
378 .get_strings = uec_get_strings, 416 .get_strings = uec_get_strings,
379 .get_ethtool_stats = uec_get_ethtool_stats, 417 .get_ethtool_stats = uec_get_ethtool_stats,
418 .get_wol = uec_get_wol,
419 .set_wol = uec_set_wol,
380}; 420};
381 421
382void uec_set_ethtool_ops(struct net_device *netdev) 422void uec_set_ethtool_ops(struct net_device *netdev)